I have an array of the following values:
X=[1 1 1 2 3 4 1 1 1 1 5 4 2 1 1 2 3 4 1 1 1 1 1 2 2 1]
I want to get the position (the index) of all the consecutive ones in the array, and construct an array that holds the start and end positions of each set of the consecutive zeros:
idx= [1 3; 7 10; 14 15; 19 23; 26 26];
I tried to use the following functions, but I am not sure how to implement it:
positionofoness= find(X==1);
find(diff(X==1));
How can I construct idx array ??
You were almost there with your find and diff solution. To find all the positions where X changes from 1, pad X with a NaN in the beginning and the end:
tmp = find(diff([NaN X NaN] == 1)) % NaN to identify 1st and last elements as start and end
tmp =
1 4 7 11 14 16 19 24 26 27
%start|end start|end
Notice that every even element tmp indicates the index + 1 of where consecutive 1s end.
idx = [reshape(tmp,2,[])]'; % reshape in desired form
idx = [idx(:,1) idx(:,2)-1]; % subtract 1 from second column
I have got two arrays with same elements... (But in different order)
e.g 1 2 12 9 7 15 22 30
and 1 2 7 12 9 20 15 22
how many swaps operations are needed to form the 2nd array from the first.?
I have tried taking no. of different elements for each index and dividing the result by 2 but that isn't fetching me the right answer...
One classic algorithm seems to be permutation cycles (https://en.m.wikipedia.org/wiki/Cycle_notation#Cycle_notation). The number of swaps needed equals the total number of elements subtracted by the number of cycles.
For example:
1 2 3 4 5
2 5 4 3 1
Start with 1 and follow the cycle:
1 down to 2, 2 down to 5, 5 down to 1.
1 -> 2 -> 5 -> 1
3 -> 4 -> 3
We would need to swap index 1 with 5, then index 5 with 2; as well as index 3 with index 4. Altogether 3 swaps or n - 2. We subtract n by the number of cycles since cycle elements together total n and each cycle represents a swap less than the number of elements in it.
1) re-index elements from 0 to n-1. In your example, arrayA becomes 0..7 and arrayB becomes 0 1 4 2 3 7 5 6.
2) sort the second array using your swapping algorithm and count the number of operations.
A bit naive, but I think you can use recursion as follows (pseudo code):
function count_swaps(arr1, arr2):
unless both arrays contain the same objects return false
if arr1.len <= 1 return 0
else
if arr1[0] == arr2[0] return count_swaps(arr1.tail, arr2.tail)
else
arr2_tail = arr2.tail
i = index_of arr1[0] in arr2_tail
arr2_tail[i] = arr2[0]
return 1+count_swaps(arr1.tail, arr2_tail)
Here's a ruby implementation:
require 'set'
def count_swaps(a1, a2)
raise "Arrays do not have the same objects: #{a1} #{a2}" unless a1.length == a2.length && Set[*a1]==Set[*a2]
return count_swap_rec(a1, a2)
end
def count_swap_rec(a1, a2)
return 0 if a1.length <= 1
return count_swaps(a1[1..-1], a2[1..-1]) if a1[0] == a2[0]
a2_tail = a2[1..-1]
a2_tail[a2_tail.find_index(a1[0])] = a2[0]
return 1 + count_swaps(a1[1..-1], a2_tail)
end
How can I find all the cells that have the same values in a multi-dimensional array?
I can get it partially to work with result=A(:,:,1)==A(:,:,2) but I'm not sure how to also include A(:,:,3)
I tried result=A(:,:,1)==A(:,:,2)==A(:,:,3) but the results come back as all 0 when there should be 1 correct answer
which is where the number 8 is located in the same cell on all the pages of the array. Note: this is just a test the repeating number could be found multiple times and as different numbers.
PS: I'm using octave 3.8.1 which is like matlab
See code below:
clear all, tic
%graphics_toolkit gnuplot %use this for now it's older but allows zoom
A(:,:,1)=[1 2 3; 4 5 6; 7 9 8]; A(:,:,2)=[9 1 7; 6 5 4; 7 2 8]; A(:,:,3)=[2 4 6; 8 9 1; 3 5 8]
[i j k]=size(A)
for ii=1:k
maxamp(ii)=max(max(A(:,:,ii)))
Ainv(:,:,ii)=abs(A(:,:,ii)-maxamp(ii));%the extra max will get the max value of all values in array
end
%result=A(:,:,1)==A(:,:,2)==A(:,:,3)
result=A(:,:,1)==A(:,:,2)
result=double(result); %turns logical index into double to do find
[row col page] = find(result) %gives me the col, row, page
This is the output it gives me:
>>>A =
ans(:,:,1) =
1 2 3
4 5 6
7 9 8
ans(:,:,2) =
9 1 7
6 5 4
7 2 8
ans(:,:,3) =
2 4 6
8 9 1
3 5 8
i = 3
j = 3
k = 3
maxamp = 9
maxamp =
9 9
maxamp =
9 9 9
result =
0 0 0
0 1 0
1 0 1
row =
3
2
3
col =
1
2
3
page =
1
1
1
Use bsxfun(MATLAB doc, Octave doc) and check to see if broadcasting the first slice is equal across all slices with a call to all(MATLAB doc, Octave doc):
B = bsxfun(#eq, A, A(:,:,1));
result = all(B, 3);
If we're playing code golf, a one liner could be:
result = all(bsxfun(#eq, A, A(:,:,1)), 3);
The beauty of the above approach is that you can have as many slices as you want in the third dimension, other than just three.
Example
%// Your data
A(:,:,1)=[1 2 3; 4 5 6; 7 9 8];
A(:,:,2)=[9 1 7; 6 5 4; 7 2 8];
A(:,:,3)=[2 4 6; 8 9 1; 3 5 8];
B = bsxfun(#eq, A, A(:,:,1));
result = all(B, 3);
... gives us:
>> result
result =
0 0 0
0 0 0
0 0 1
The above makes sense since the third row and third column for all slices is the only value where every slice shares this same value (i.e. 8).
Here's another approach: compute differences along third dimension and detect when all those differences are zero:
result = ~any(diff(A,[],3),3);
You can do
result = A(:,:,1) == A(:,:,2) & A(:,:,1) == A(:,:,3);
sum the elements along the third dimension and divide it with the number of dimensions. We get back the original value if the values are the same in all dimension. Otherwise a different (e.g. a decimal) value. Then find the location where A and the summation are equal over the third dimension.
all( A == sum(A,3)./size(A,3),3)
ans =
0 0 0
0 0 0
0 0 1
or
You could also do
all(A==repmat(sum(A,3)./size(A,3),[1 1 size(A,3)]),3)
where repmat(sum(A,3)./size(A,3),[1 1 size(A,3)]) would highlight the implicit broadcasting of this when compared with A.
or
you skip the broadcasting altogether and just compare it with the first slice of A
A(:,:,1) == sum(A,3)./size(A,3)
Explanation
3 represents the third dimension .
sum(A,3) means that we are taking the sum over the third dimension.
Then we divide that sum by the number of dimensions.
It's basically the average value for that position in the third dimension.
If you add three values and then divide it by three then you get the original value back.
For example, A(3,3,:) is [8 8 8]. (8+8+8)/3 = 8.
If you take another example, i.e. the value above, A(2,3,:) = [6 4 1].
Then (6+4+1)/3=3.667. This is not equal to A(2,3,:).
sum(A,3)./size(A,3)
ans =
4.0000 2.3333 5.3333
6.0000 6.3333 3.6667
5.6667 5.3333 8.0000
Therefore, we know that the elements are not the same
throughout the third dimension. This is just a trick I use
to determine that. You also have to remember that
sum(A,3)./size(A,3) is originally a 3x3x1 matrix
that will be automatically expanded (i.e. broadcasted) to a
3x3x3 matrix when we do the comparison with A (A == sum(A,3)./size(A,3)).
The result of that comparison will be a logical array with 1 for the positions that are the same throughout the third dimension.
A == sum(A,3)./size(A,3)
ans =
ans(:,:,1) =
0 0 0
0 0 0
0 0 1
ans(:,:,2) =
0 0 0
1 0 0
0 0 1
ans(:,:,3) =
0 0 0
0 0 0
0 0 1
Then use all(....,3) to get those. The result is a 3x3x1
matrix where a 1 indicates that the value is the same in the
third dimension.
all( A == sum(A,3)./size(A,3),3)
ans =
0 0 0
0 0 0
0 0 1
I have the following array: A = [2 7 8 9 10] and I'm looking for a way to group its subsequent elements, so to get a result like B = [1 2; 4 7], where the first column returns the number of subsequent elements, and the second the value of the first element.
How do you suggest to approach the problem?
Try this:
idx = find([[0 diff(A)] ~= 1 1]);
B = [diff(idx); A(idx(1:end-1))].';
The logic is this:
You're interested to know when a subsequent sequence starts. You could use the diff function to calculate the difference between each element and the previous one, like this:
>> A = [2 7 8 9 10]
>> diff(A)
ans =
5 1 1 1
We want to focus on values different than 1 (because they are within a sequence). The 5, in this case, represents the start of the 7,8,9,10 sequence. Also, the first element always start a sequence. We may "force" this by adding a 0 to the response, like this:
>> [0 diff(A)]
ans =
0 5 1 1 1
Now, we need to get the numbers different than 1:
>> [0 diff(A)] ~= 1
ans =
1 1 0 0 0
As we want to know the length of the sequence, it would be interesting to know the end of the last sequence. For that, we add a 1 in the end:
>> [[0 diff(A)] ~= 1 1]
ans =
1 1 0 0 0 1
Now we use find to get the indexes of the 1's:
>> idx = find([[0 diff(A)] ~= 1 1])
ans =
1 2 6
It tells us we have two sequences: the first one starts on 1 and ranges from 1..2-1, and the second one starts on 2 and ranges from 2..6-1. If we do a diff of idx, we get the lenghts:
>> diff(idx)
ans =
1 4
To get the values, we index A using idx (ignoring the last value):
>> A(idx(1:end-1))
ans =
2 7
The last line just combines this into a row matrix, and transposes it:
>> B = [diff(idx); A(idx(1:end-1))].'
ans =
1 2
4 7
I have an array that looks something like...
1 0 0 1 2 2 1 1 2 1 0
2 1 0 0 0 1 1 0 0 2 1
1 2 2 1 1 1 2 0 0 1 0
0 0 0 1 2 1 1 2 0 1 2
however my real array is (50x50).
I am relatively new to MATLAB and need to be able to count the amount of unique values in each row and column, for example there is four '1's in row-2 and three '0's in column-3. I need to be able to do this with my real array.
It would help even more if these quantities of unique values were in arrays of their own also.
PLEASE use simple language, or else i will get lost, for example if representing an array, don't call it x, but perhaps column_occurances_array... for me please :)
What I would do is iterate over each row of your matrix and calculate a histogram of occurrences for each row. Use histc to calculate the occurrences of each row. The thing that is nice about histc is that you are able to specify where the bins are to start accumulating. These correspond to the unique entries for each row of your matrix. As such, use unique to compute these unique entries.
Now, I would use arrayfun to iterate over all of your rows in your matrix, and this will produce a cell array. Each element in this cell array will give you the counts for each unique value for each row. Therefore, assuming your matrix of values is stored in A, you would simply do:
vals = arrayfun(#(x) [unique(A(x,:)); histc(A(x,:), unique(A(x,:)))], 1:size(A,1), 'uni', 0);
Now, if we want to display all of our counts, use celldisp. Using your example, and with the above code combined with celldisp, this is what I get:
vals{1} =
0 1 2
3 5 3
vals{2} =
0 1 2
5 4 2
vals{3} =
0 1 2
3 5 3
vals{4} =
0 1 2
4 4 3
What the above display is saying is that for the first row, you have 3 zeros, 5 ones and 3 twos. The second row has 5 zeros, 4 ones and 2 twos and so on. These are just for the rows. If you want to do these for columns, you have to modify your code slightly to operate along columns:
vals = arrayfun(#(x) [unique(A(:,x)) histc(A(:,x), unique(A(:,x)))].', 1:size(A,2), 'uni', 0);
By using celldisp, this is what we get:
vals{1} =
0 1 2
1 2 1
vals{2} =
0 1 2
2 1 1
vals{3} =
0 2
3 1
vals{4} =
0 1
1 3
vals{5} =
0 1 2
1 1 2
vals{6} =
1 2
3 1
vals{7} =
1 2
3 1
vals{8} =
0 1 2
2 1 1
vals{9} =
0 2
3 1
vals{10} =
1 2
3 1
vals{11} =
0 1 2
2 1 1
This means that in the first column, we see 1 zero, 2 ones and 1 two, etc. etc.
I absolutely agree with rayryeng! However, here is some code which might be easier to understand for you as a beginner. It is without cell arrays or arrayfuns and quite self-explanatory:
%% initialize your array randomly for demonstration:
numRows = 50;
numCols = 50;
yourArray = round(10*rand(numRows,numCols));
%% do some stuff of what you are asking for
% find all occuring numbers in yourArray
occVals = unique(yourArray(:));
% now you could sort them just for convinience
occVals = sort(occVals);
% now we could create a matrix occMat_row of dimension |occVals| x numRows
% where occMat_row(i,j) represents how often the ith value occurs in the
% jth row, analoguesly occMat_col:
occMat_row = zeros(length(occVals),numRows);
occMat_col = zeros(length(occVals),numCols);
for k = 1:length(occVals)
occMat_row(k,:) = sum(yourArray == occVals(k),2)';
occMat_col(k,:) = sum(yourArray == occVals(k),1);
end