Matlab - replicating arrays values according to occurrences array - arrays

For example, A = [19 20 21 22 23 24 25]; B = [2 0 3 0 0 0 2];
How can we get a new array, repeating each value from B accordingly X times?
For example, answer here is: [19 19 21 21 21 25 25].
Please note that I am only allowed to a for loop combined with a repmat call.

If you are only allowed to use repmat and a for loop, you can do the following:
S = [];
for idx = 1 : length(B)
S = [S repmat(A(idx), 1, B(idx))];
end
S is initially a blank array, then for as many values as there are in B (or A since they're both equal in length), simply concatenate S with each value in A that is repeated by the corresponding number in B. S will contain the output.
By running the above example, I get:
S =
19 19 21 21 21 25 25
However, I highly recommend you use more vectorized approaches. I'll leave that to you as an exercise.
Good luck!

Related

Matlab make new array of values without a loop

In Matlab, I don't know the best way to explain this except for an example. Let's say I have an array called tStart and a tDuration length:
tStart = [3,8,15,20,25];
tDuration = 2;
Is there some way to get a new array such that it would be:
[3,4,5,8,9,10,15,16,17,20,21,22,25,26,27]
So what I want is to use the initial tStart array then make up a new array with the starting value and then next corresponding values for the length of tDuration.
If I do [tStart(1:end)+tDuration] I get an array of ending values, but how can I get the start, end, and all the values in between?
If I [tStart(1:end):tStart(1:end)+tDuration] I get an error.
Any help of a way to do this without a loop would be greatly appreciated.
I would use MATLAB's implicit expansion, reshape, and the ordering of 2d arrays.
First, create a 2d array containing the desired values from tStart:
tStart = [3,8,15,20,25];
tDuration = 2;
tDurAdd = [0:tDuration].'; % numbers to add to tStart
tArray = tStart + tDurAdd;
This gives us
tArray =
3 8 15 20 25
4 9 16 21 26
5 10 17 22 27
These are the correct values, now we just have to reshape them to a row vector:
tResult = reshape(tArray, 1, []);
The final array is:
tResult =
3 4 5 8 9 10 15 16 17 20 21 22 25 26 27
Of course, this can all be done on one line:
tResult = reshape(tStart + [0:tDuration].', 1, []);

How to identify breaks within an array of MATLAB?

I have an array in MATLAB containing elements such as
A=[12 13 14 15 30 31 32 33 58 59 60];
How can I identify breaks in values of data? For example, the above data exhibits breaks at elements 15 and 33. The elements are arranged in ascending order and have an increment of one. How can I identify the location of breaks of this pattern in an array? I have achieved this using a for and if statement (code below). Is there a better method to do so?
count=0;
for i=1:numel(A)-1
if(A(i+1)==A(i)+1)
continue;
else
count=count+1;
q(count)=i;
end
end
Good time to use diff and find those neighbouring differences that aren't equal to 1. However, this will return an array which is one less than the length of your input array because it finds pairwise differences up until the last element, so naturally there will be one less. As such, when you find the locations that aren't equal to 1, make sure you add 1 to the locations to account for this:
>> A=[12 13 14 15 30 31 32 33 58 59 60];
>> q = find(diff(A) ~= 1) + 1
q =
5 9
This tells us that locations 5 and 9 in your array is where the jump happens, and that's right for your example data.
However, if you want to find the locations before the jump happens, such as in your code, don't add 1 to the result:
>> q = find(diff(A) ~= 1)
q =
4 8

how to take diffrence between cell array and simple integer array in matlab?

i have extracted 23 sentences from a text file which are divided and shown in separate line each sentence is given a number in ascending order {1,2,3,...}, code i used for this is as follows:
sentences = regexp(F,'\S.*?[\.\!\?]','match')
char(sentences)
now i did some processing and got filtered answer which shows a subset of sentences as shown below:
result = 1 4 5 9 11 14 16 17
the code i used for result is as follows:
result = unique([OccursTogether{:}]);
display(result)
now what i want to do is to show the sentences that are not present in the result variable for example the result i need is as follows:
result2 = 2 3 6 7 8 10 12 13 15 18 19 20 21 22 23
remember sentences is [1*N] cell where as result is simple array saving integers.
The function you are looking for is setdiff:
%// Create an array containing the indices of all the sentences
AllSentences = 1:23;
%// Indices of sentences present
result = [1 4 5 9 11 14 16 17]
%// And not present
NotPresent = setdiff(AllSentences,result)
NotPresent =
Columns 1 through 13
2 3 6 7 8 10 12 13 15 18 19 20 21
Columns 14 through 15
22 23
I'm not sure to understand what is a cell array and what is not, but for cell arrays you can convert them to numeric arrays using cell2mat and apply the same methodology.
Eg:
AllSentences = {1:23};
NotPresent = setdiff(cell2mat(AllSentences),result)

check if ALL elements of a vector are in another vector

I need to loop through coloumn 1 of a matrix and return (i) when I have come across ALL of the elements of another vector which i can predefine.
check_vector = [1:43] %% I dont actually need to predefine this - i know I am looking for the numbers 1 to 43.
matrix_a coloumn 1 (which is the only coloumn i am interested in looks like this for example
1
4
3
5
6
7
8
9
10
11
12
13
14
16
15
18
17
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
1
3
4
2
6
7
8
We want to loop through matrix_a and return the value of (i) when we have hit all of the numbers in the range 1 to 43.
In the above example we are looking for all the numbers from 1 to 43 and the iteration will end round about position 47 in matrix_a because it is at this point that we hit number '2' which is the last number to complete all numbers in the sequence 1 to 43.
It doesnt matter if we hit several of one number on the way, we count all those - we just want to know when we have reached all the numbers from the check vector or in this example in the sequence 1 to 43.
Ive tried something like:
completed = []
for i = 1:43
complete(i) = find(matrix_a(:,1) == i,1,'first')
end
but not working.
Assuming A as the input column vector, two approaches could be suggested here.
Approach #1
With arrayfun -
check_vector = [1:43]
idx = find(arrayfun(#(n) all(ismember(check_vector,A(1:n))),1:numel(A)),1)+1
gives -
idx =
47
Approach #2
With customary bsxfun -
check_vector = [1:43]
idx = find(all(cumsum(bsxfun(#eq,A(:),check_vector),1)~=0,2),1)+1
To find the first entry at which all unique values of matrix_a have already appeared (that is, if check_vector consists of all unique values of matrix_a): the unique function almost gives the answer:
[~, ind] = unique(matrix_a, 'first');
result = max(ind);
Someone might have a more compact answer but is this what your after?
maxIndex = 0;
for ii=1:length(a)
[f,index] = ismember(ii,a);
maxIndex=max(maxIndex,max(index));
end
maxIndex
Here is one solution without a loop and without any conditions on the vectors to be compared. Given two vectors a and b, this code will find the smallest index idx where a(1:idx) contains all elements of b. idx will be 0 when b is not contained in a.
a = [ 1 4 3 5 6 7 8 9 10 11 12 13 14 16 15 18 17 19 20 21 22 23 24 25 26 ...
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 1 3 4 2 6 7 8 50];
b = 1:43;
[~, Loca] = ismember(b,a);
idx = max(Loca) * all(Loca);
Some details:
ismember(b,a) checks if all elements of b can be found in a and the output Loca lists the indices of these elements within a. The index will be 0, if the element cannot be found in a.
idx = max(Loca) then is the highest index in this list of indices, so the smallest one where all elements of b are found within a(1:idx).
all(Loca) finally checks if all indices in Loca are nonzero, i.e. if all elements of b have been found in a.

Vectorized range checking in Matlab

In trying to port an algorithm from C# to Matlab I found that Matlab is inefficient at running for loops. As such I want to vectorize the algorithm.
I have following inputs:
lowrange:
[ 00 10 20 30 40 50 ... ]
highrange:
[ 10 20 30 40 50 60 ... ]
These arrays are equal in length.
I now have a third array Values (which could be any length) and for this array I want to count the occurrences of Values elements between lowerange(i) and highrange(i) (You can see I'm coming from a for loop).
The output should be an array of length lowrange/highrange.
So with the above arrays and input LineData:
[ 1 2 3 4 6 11 12 16 31 34 45 ]
I expect to get:
[ 05 03 00 02 01 00 ... ]
I tried the (for me) obvious thing:
LineData(LineData < PixelEnd & LineData > PixelStart)
But that doesn't work because it just checks LineData on an element by element way. It does not try to apply the comparison over all values in LineData.
Unfortunately, I cannot come up with anything else since I'm not yet used to think in a Matlab 'vector' way, let alone knowing all applicable instructions from memory.
As you are looking to do a basic histogram with given edges, you can use Matlabs built-in function histc:
values = [ 1 2 3 4 6 11 12 16 31 34 45 ];
edges = 0:10:60;
histc(values, edges)
ans =
5 3 0 2 1 0 0
For ranges with identical intervals and starting from 0, here's a bsxfun based counting approach -
LineData = [ 1 2 3 4 6 11 12 16 31 34 45 ] %// Input
interval = 10; %// interval width
num_itervals = 6; %// number of intervals
%// Get matches for each interval and sum them within each interval for the counts
out = sum(bsxfun(#eq,ceil(LineData(:)/interval),1:num_itervals))
Output -
LineData =
1 2 3 4 6 11 12 16 31 34 45
out =
5 3 0 2 1 0
Assuming that the last interval would be the one holding the max of input data, you can try out a diff + indexing based approach too -
LineData = [ 1 2 3 4 6 11 12 16 31 34 45 ] %// Input
interval = 10; %// interval width
labels = ceil(LineData(:)/interval); %// set labels to each input entry
df_labels = diff(labels)~=0; %// mark the change of labels
df_labels_pos = find([df_labels; 1]); %// get the positions of label change
intv_pos= labels([true;df_labels]);%// position of each interval with nonzero counts
%// get counts from interval between label position change and put at right places
out(intv_pos) = [ df_labels_pos(1) ; diff(df_labels_pos)];

Resources