Find the position of equal elements in a matrix using Matlab - matlab

Suppose I have:
m = [1,2,3;1,4,5;6,4,7]
I want to get a list containing the positions of the elements in the matrix m so that the positions of equal elements are grouped together. The output for matrix m must be:
{{1,1},{2,1}},{{2,2},{3,2}},{1,2},{1,3},{2,3},{3,1},{3,3}
% 1 2 3 4 5 6 7
We can see here that the positions for the elements that are all equal to each other are grouped together.

The simplest way would be to loop through every unique value and determine the row and column positions that match each value. Something like this could work:
val = unique(m);
pos = cell(1, numel(val));
for ii = 1 : numel(val)
[r,c] = find(m == val(ii));
pos{ii} = [r,c];
end
pos would be a cell array containing all of the positions for each unique value. We can show what these positions are by:
>> format compact; celldisp(pos)
pos{1} =
1 1
2 1
pos{2} =
1 2
pos{3} =
1 3
pos{4} =
2 2
3 2
pos{5} =
2 3
pos{6} =
3 1
pos{7} =
3 3
This of course is not meaningful unless you specifically show each unique value per group of positions. Therefore, we can try something like this instead where we can loop through each element in the cell array as well as display the corresponding element that each set of positions belongs to:
for ii = 1 : numel(val)
fprintf('Value: %f\n', val(ii));
fprintf('Positions:\n');
disp(pos{ii});
end
What I get is now:
Value: 1.000000
Positions:
1 1
2 1
Value: 2.000000
Positions:
1 2
Value: 3.000000
Positions:
1 3
Value: 4.000000
Positions:
2 2
3 2
Value: 5.000000
Positions:
2 3
Value: 6.000000
Positions:
3 1
Value: 7.000000
Positions:
3 3

This gives you what you want, except for the fact that indices of unique elements are also wrapped in cell twice, just like the indices of repeating elements:
m = [1,2,3;1,4,5;6,4,7];
[~, idx] = ismember(m(:), unique(m(:)));
linInd = 1:numel(m);
[i,j] = ind2sub(size(m), linInd);
res = accumarray(idx, linInd, [], #(x) {num2cell([i(x);j(x)]',2)});
Result:
>> celldisp(res)
res{1}{1} =
2 1
res{1}{2} =
1 1
res{2}{1} =
1 2
res{3}{1} =
1 3
res{4}{1} =
2 2
res{4}{2} =
3 2
res{5}{1} =
2 3
res{6}{1} =
3 1
res{7}{1} =
3 3

Related

count adjacent elements in vector with repetitions - matlab

v = [1,1,1,2,3,3,4,4,4,4,2,3,3,3,1,1]
I'm looking for a way to count adjacent elements in vector c without loosing the repetitions.
This is the desired output:
c =
3 1 2 4 1 3 2
Use diff() to spot the change points, then get the indexes of those points.
id = diff(v)==0;
idx = strfind([id 0], 0);
c = [idx(1) diff(idx)]
Output:
c =
3 1 2 4 1 3 2
Answer from Mathworks
% code
v = [1,1,1,2,3,3,4,4,4,4,2,3,3,3,1,1];
c = diff([0 find(diff(v)) numel(v)])
% output
c = [3 1 2 4 1 3 2]

How find rows and columns in matlab

I have variable matrix :
A = [1 2 8 8 1
4 6 8 1 1
5 3 1 1 8];
and I have variable B :
B=[2 3 1 8 8];
Question is how to find rows and columns (sort by rows) in variable A from variable B.
Example, first index in variable B is 2, and then I want to find value 2 in variable A and get to first rows and columns, and next process until index 5, but if rows and columns has been used so get second position (ex. index 4 & 5 having same value).
rows;
columns;
Result is:
rows = 1 3 1 1 1
columns = 2 2 1 3 4
Use can use find and sub2ind to achieve what you want
but for that you have to take transpose of your A first
A = [1 2 8 8 1
4 6 8 1 1
5 3 1 1 8];
B= [2 3 1 8 8];
TMP = A.';
for i = 1:length(B)
indx = find(TMP== B(i),1,'first') %Finding the element of B present in A
if(~isempty(indx )) % If B(i) is a member of A
[column(i),row(i)] = ind2sub(size(TMP),indx) % store it in row and column matrix
TMP(indx) = nan; % remove that element
end
end
column =
2 2 1 3 4
row =
1 3 1 1 1
As in one of the comments Usama suggested preallocation of memory
you can do that by using
row = zeros(1,sum(ismember(B,A)))
column= zeros(1,sum(ismember(B,A)))
The above code works even if there are some members of B not present in A
Use find. The function could return both a linear index or a row/col index.
Using linear index a solution could be
idx = zeros(size(B));
for i = 1:numel(B)
% Find all indexes
tmpIdx = find(A == B(i));
% Remove those already used
tmpIdx = setdiff(tmpIdx, idx);
% Get the first new unique
idx(i) = tmpIdx(1);
end
% Convert index to row and col
[rows, cols] = ind2sub(size(A),idx)
Giving:
rows = 1 3 1 1 2
cols = 2 2 1 3 3
Note that as the linear indexing goes down column by column, the result here differs from the one in your example (although still a correct index)
rows = 1 3 1 1 1
columns= 2 2 1 3 4
But to get this you could just transpose the A matrix (A.') and flip the rows and cols (the result from ind2sub)
Here is on solution where I use for loop, I tried to optimize the number of iteration and the computational cost. If there is no corresponding value between B and A the row/col index return NaN.
[Bu,~,ord] = unique(B,'stable');
% Index of each different values
[col,row] = arrayfun(#(x) find(A'==x),Bu,'UniformOutput',0)
% For each value in vector B we search the first "non already used" corresponding value in A.
for i = 1:length(B)
if ~isempty(row{ord(i)})
r(i) = row{ord(i)}(1);
row{ord(i)}(1) = [];
c(i) = col{ord(i)}(1);
col{ord(i)}(1) = [];
else
r(i) = NaN;
c(i) = NaN;
end
end
RESULT:
c = [2 2 1 3 4]
r = [1 3 1 1 1]

Position of integers in vector

I think the question is pretty basic, but still keeps me busy since some time.
Lets assume we have a vector containing 4 integers randomly repetetive, like:
v = [ 1 3 3 3 4 2 1 2 3 4 3 2 1 4 3 3 4 2 2]
I am searching for the vector of all positions of each integer, e.g. for 1 it should be a vector like:
position_one = [1 7 13]
Since I want to search every row of a 100x10000 matrix I was not able to deal with linear indeces.
Thanks in advance!
Rows and columns
Since your output for every integer changes, a cell array will fit the whole task. For the whole matrix, you can do something like:
A = randi(4,10,30); % some data
Row = repmat((1:size(A,1)).',1,size(A,2)); % index of the row
Col = repmat((1:size(A,2)),size(A,1),1); % index of the column
pos = #(n) [Row(A==n) Col(A==n)]; % Anonymous function to find the indices of 'n'
than for every n you can write:
>> pos(3)
ans =
1 1
2 1
5 1
6 1
9 1
8 2
3 3
. .
. .
. .
where the first column is the row, and the second is the column for every instance of n in A.
And for all ns you can use an arrayfun:
positions = arrayfun(pos,1:max(A(:)),'UniformOutput',false) % a loop that goes over all n's
or a simple for loop (faster):
positions = cell(1,max(A(:)));
for n = 1:max(A(:))
positions(n) = {pos(n)};
end
The output in both cases would be a cell array:
positions =
[70x2 double] [78x2 double] [76x2 double] [76x2 double]
and for every n you can write positions{n}, to get for example:
>> positions{1}
ans =
10 1
2 3
5 3
3 4
5 4
1 5
4 5
. .
. .
. .
Only rows
If all you want in the column index per a given row and n, you can write this:
A = randi(4,10,30);
row_pos = #(k,n) A(k,:)==n;
positions = false(size(A,1),max(A(:)),size(A,2));
for n = 1:max(A(:))
positions(:,n,:) = row_pos(1:size(A,1),n);
end
now, positions is a logical 3-D array, that every row corresponds to a row in A, every column corresponds to a value of n, and the third dimension is the presence vector for the combination of row and n. this way, we can define R to be the column index:
R = 1:size(A,2);
and then find the relevant positions for a given row and n. For instance, the column indices of n=3 in row 9 is:
>> R(positions(9,3,:))
ans =
2 6 18 19 23 24 26 27
this would be just like calling find(A(9,:)==3), but if you need to perform this many times, the finding all indices and store them in positions (which is logical so it is not so big) would be faster.
Find linear indexes in a matrix: I = find(A == 1).
Find two dimensional indexes in matrix A: [row, col] = find(A == 1).
%Create sample matrix, with elements equal one:
A = zeros(5, 4);
A([2 10 14]) = 1
A =
0 0 0 0
1 0 0 0
0 0 0 0
0 0 1 0
0 1 0 0
Find ones as linear indexes in A:
find(A == 1)
ans =
2
10
14
%This is the same as reshaping A to a vector and find ones in the vector:
B = A(:);
find(B == 1);
B' =
0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0
Find two dimensional indexes:
[row, col] = find(A == 1)
row =
2
5
4
col =
1
2
3
You can do that with accumarray using an anonymous function as follows:
positions = accumarray(v(:), 1:numel(v), [], #(x) {sort(x.')});
For
v = [ 1 3 3 3 4 2 1 2 3 4 3 2 1 4 3 3 4 2 2];
this gives
positions{1} =
1 7 13
positions{2} =
6 8 12 18 19
positions{3} =
2 3 4 9 11 15 16
positions{4} =
5 10 14 17

Finding elements who meet a specific condition

I've a matrix A and I'd like to find elements of first row which have 1 in the second row. i.e. for following matrix
A=
2 5 6 1
1 0 0 1
I'd like to have output as hits = [2 1] without using loops. and then finds the maximum items in the answer. i.e. (2>1) so my final answer is 2. The response is probably using arrayfun but I've problems and get errors using it. What is the correct syntax?
Thanks
Try this:
out = max(A(1,A(2,:) == 1))
Example:
>> A
A =
2 5 6 1
1 0 0 1
>> out
out =
2
Explanation: (if you need)
%// create a mask of which column you want
mask = A(2,:) == 1 %// by checking all values of 2nd row with 1
%// get only the values of row one, meeting 'the' condition
hits = A(1,mask)
%// Find the maximum from that
maxHits = max(hits)
For Cell Array using cellfun
A = {[2 5 6 1; 1 0 0 1], [2 3 2 5 4; 1 1 3 1 2]} %// eg input
A =
[2x4 double] [2x5 double]
out = cellfun(#(x) max(x(1,x(2,:) == 1)),A)
out =
2 5

Find set intersection of multiple arrays in MATLAB

I tried to solve this problem, but I could not implement.
Could you help me anything for this?
Problem
Mat1 | Mat2 | Mat3
1 2 | 1 3 | 2 6
1 3 | 2 6 | 2 5
2 4 | 3 1 | 3 1
3 1 | 3 5 | 5 2
4 5 |
When there are 3 matrices(for example above), I want to get this result for the intersection rows in [column1 column2 matrixnumber] form.
The result for above example would be
1 3 1
1 3 2
2 6 2
2 6 3
3 1 1
3 1 2
3 1 3
It would be OK if the result is in the form [column1 column2 firstmatrix secondmatrix, ...]
1 3 1 2
2 6 2 3
3 1 1 2 3
For this problem, I want to use at most one for-loop.
Do you have any idea for this?
Here an alternative solution (which seems to run faster than Gunther's) using MATLAB's intersect:
Mat = {[1 2; 1 3; 2 4; 3 1; 4 5],
[1 3; 2 6; 3 1; 3 5],
[2 6; 2 5; 3 1; 5 2]};
result = zeros(sum(cellfun(#(x)size(x, 1), Mat)), 3); % # Preallocate memory
k = 1;
for cc = transpose(nchoosek(1:numel(Mat), 2))
x = intersect(Mat{cc}, 'rows'); % # Find intersection
y = ones(size(x, 1), 2) * diag(cc); % # Generate matrix indices
result(k:k + numel(y) - 1, :) = [[x; x], y(:)];
k = k + numel(y);
end
result(all(~result, 2), :) = []; % # Discard zero rows
result = unique(result, 'rows'); % # Discard repeated rows
The matrix result should now contain the unique intersection rows and their corresponding matrix indices, just like you want:
result =
1 3 1
1 3 2
2 6 2
2 6 3
3 1 1
3 1 2
3 1 3
If I understand correctly, you have a number of sets of pairs: Mat1,Mat2, Mat3, ... MatN. Now you want to find the unique pairs and then find out in which set every unique pair appears.
If you have a large number of sets, I suggest you start using a cell array to hold them all, makes things a lot easier:
N = 3; % total number of data sets
Mat = cell(N,1);
Mat{1} = [1 2;
1 3;
2 4;
3 1;
4 5];
Mat{2} = [1 3;
2 6;
3 1;
3 5];
Mat{3} = [2 6;
2 5;
3 1;
5 2];
% etc.
First let's find the unique pairs:
uniq_pairs = unique(cat(1,Mat{:}),'rows');
M = size(uniq_pairs ,1);
Then use ismember to check which sets contain which pairs:
matcontpair = false(M,N); %preallocate
for ii=1:N % unavoidable loop
matcontpair(:,ii) = ismember(uniq_pairs,Mat{ii},'rows');
end
To translate this intersection matrix to a set of matrix numbers for each pair, loop through it again and store the final result in a cell array (you can't use an array, because they might not be of same size (some pairs only found once, other twice, other three times ...)
pair_occurence= cell(M,1);
d=1:N;
for jj=1:M
pair_occurence{jj} = d(matcontpair(jj,:));
end
Now you have a matrix uniq_pairs of size Mx2 containing the unique pairs, and a occurence cell array pair_occurence of size Mx1: each cell corresponds to a pair and contains a list of matrices where the pair is present.
If you want to remove pairs from the list which are only present in one matrix, use the following:
% find them
lonely_pairs = cellfun(#numel,pair_occurence)<2;
% and destroy them
uniq_pairs(lonely_pairs,:) = [];
pair_occurence(lonely_pairs) = [];