Find a pair of numbers in a matrix in Matlab - matlab

Given the matrix A = [6 4 1; 1 4 3; 3 4 2;7 6 8] and the array of pairs b = [4 6; 4 1; 1 6], I want to find the pairs given in b in the rows of A without a for loop.
For example, the first pairs is (4,6) or (6,4) , which occurs in the first row of A.

Assuming, you want to find the rows of A which contain the exact pairs given in b, this is how you can do it without a loop:
% Create a matrix of pairs in A
pairs = cat(3, A(:, 1:end-1), A(:, 2:end));
% Reshape b to use bsxfun
b_ = reshape(b', [1 1 size(b')]);
% Get the matches for the pairs and for the flipped pairs
indices = all( bsxfun(#eq, pairs, b_), 3) | all( bsxfun(#eq, pairs, flip(b_,3)), 3);
% Find the indices of the rows with a match
row_indices = find(squeeze(any(any(indices,4),2)));
Please refer to the reference on vectorization for more information on how to make fast computations in Matlab without loops.

Related

Pairs of positions of equal elements of a matrix in Matlab

I have a row vector A in Matlab containing possibly repeated integers. I would like your help to construct a matrix B reporting all possible pairs of positions of equal elements of A. As stated in the comments below, the hard part is that I don't want to list in B "redundant" pairs.
Let me explain better with an example.
clear
A=[100 101 100 100 101 200];
We can see that
%A(1)=A(3)=A(4);
%A(2)=A(5);
Hence,
B=[1 3; 1 4; 2 5];
or, equivalently,
B=[1 3; 3 4; 2 5];
B=[1 4; 3 4; 2 5];
I am indifferent among getting any of the three vectors B reported above.
Notice that I don't want
B=[1 3; 1 4; 3 4; 2 5];
as one of the pairs among (1,3), (1,4), (3,4) is redundant, i.e., if A(1)=A(3) and A(1)=A(4), then A(4)=A(3) and similarly for other combinations.
I tried with unique but none of the outputs delivered by unique seems to give the desired matrix. Any help?
If you don't like to use loops, As suggested in the #Wolfie's answer, you can use accumarray:
[~,~,idx]=unique(A,'stable');
B = accumarray ...
( ...
idx(:), ...
(1:numel(A)).', ...
[], ...
#(x) ...
{ ...
[repmat(x(1),numel(x)-1,1) x(2:end,1)] ...
} ...
);
result = vertcat(B{:})
The part which requires thinking here is the redundant pairings. The easiest approach to remove redundant pairings is to have one key index for each value, and link all matching values to that index.
In the case of your example, this means using the following relations
% A(1) = A(3)
% A(1) = A(4)
% A(2) = A(5)
It's implied by any equivalences to the first of each value that, for instance, A(3)=A(4).
To do this, we can use the last indexing output from unique, then loop through to set up this equivalence indexing. See the below code, with comments for understanding:
% A is the input row vector
A=[100 101 100 100 101 200];
% Get the 'unique' indexing output
[~, ~, juA] = unique(A);
% Set up output as cell so we don't have to worry about how many rows each
% equivalence will take up.
B = cell( max(juA), 1 );
% Loop through all of the unique indices
for ii = 1:max(juA)
% Get indices where the value is equal to the current value
k = find( juA == ii );
% Output for this value is [1 x; 1 y; 1 z; ...] where x/y/z are indices
% of equivalent values
B{ii} = [repmat(k(1), numel(k)-1, 1), k(2:end)];
end
% Concatenate cell array B to be a 2 column numeric array
B = vertcat(B{:});
Output:
>> B = [1 3; 1 4; 2 5]

Convert a cell containing matrices to a 2d matrix

I want to find easy way to convert a 1x324 cell array which contains matrices to a 2-dimensional matrix.
Each of the cell array's elements is a matrix of size 27x94, so they contain 2538 different values. I want to convert this cell array of matrices to a 324x2538 matrix - where the rows of the output contain each matrix (as a row vector) from the cell array.
To clarify what my data looks like and what I'm trying to create, see this example:
matrix1 = [1,2,3,4,...,94 ; 95,96,97,... ; 2445,2446,2447,...,2538]; % (27x94 matrix)
% ... other matrices are similar
A = {matrix1, matrix2, matrix3, ..., matrix324}; % Matrices are in 1st row of cell array
What I am trying to get:
% 324x2538 output matrix
B = [1 , 2 , ..., 2538 ; % matrix1
2539 , 2540, ..., 5076 ; % matrix2
...
819775, 819776, ..., 822312];
The cell2mat function does exactly that. The doc example:
C = {[1], [2 3 4];
[5; 9], [6 7 8; 10 11 12]};
A = cell2mat(C)
A =
1 2 3 4
5 6 7 8
9 10 11 12
You have your matrix now, so just rework it to contain rows:
B = rand(27,302456); % your B
D = reshape(B,27,94,324); % stack your matrices to 3D
E = reshape(D,1, 2538,324); % reshape each slice to a row vector
E = permute(E,[3 2 1]); % permute the dimensions to the correct order
% Based on sizes instead of fixed numbers
% D = reshape(B, [size(A{1}) numel(A)]);
% E = reshape(D,[1 prod(size(A{1})) numel(A)]);
% E = permute(E,[3 2 1]); % permute the dimensions to the correct order
Or, to one line it from your B:
B = reshape(B,prod(size(A{1})),numel(A)).'
One way to write this would be using cellfun to operate on each element of the cell, then concatenating the result.
% Using your input cell array A, turn all matrices into column vectors
% You need shiftdim so that the result is e.g. [1 2 3 4] not [1 3 2 4] for [1 2; 3 4]
B = cellfun(#(r) reshape(shiftdim(r,1),[],1), A, 'uniformoutput', false);
% Stack all columns vectors together then transpose
B = [B{:}].';
Now I found the solution and I will add it here if anyone have similar problems in future:
for ii = 1:length(A)
B{ii} = A{ii}(:);
end
B = cell2mat(B).';

How to get the indices of max values in a matrix,and map them to the indices of another same sized matrix?

I have two 16x12 matrices, In matrix A, I should sort in descending order and find the first 10 max values. But I should know the max values' indices before being sorted.
Finally, I should give those indices to the second matrix and find the values in that matrix.
I tried with for-loop but it doesn't give me accurate answer.
This should work:
[~,I] = sort(A(:), 'descend');
vals = B(I(1:10));
For example:
>> A = [ 4 2; 1 5];
>> B = [ 7 8; 0 NaN];
>> [~,I] = sort( A(:), 'descend' );
>> vals = B(I(1:2))
vals =
NaN
7

MATLAB/OCTAVE Extracting elements from different sized vectors in a cell array

I have a simple question but I can't figure it out or find it anywhere.
I have a cell array where c{1} is a vector and c{2} is a vector but of different lengths, up to c{i}. What I want is one vector that is [c{1};c{2};c{3}...c{i}]. What is the most efficient way to do this?
The following one-liner even works for completely inconsistent inputs:
result = [cell2mat(cellfun(#(x) x(:), A, 'uni', 0)')]'
Example:
for:
A{1} = [1, 2, 3, 4, 5];
A{2} = [6; 7; 8; 9];
A{3} = [10, 12; 11, 13];
it returns:
result =
1 2 3 4 5 6 7 8 9 10 11 12 13
Matlab/Octave allows this king of really-not-efficient but very-convenient notation, assuming a is a structure only containing column-vectors:
x = []; #% A fresh new vector/matrix/tensor, who knows?
for i=1:numel(a) #% parse container item by item
x = [x;a{i}]; #% append container item a{i} to x in a column-fashion way
end
This will works but it is bloody inefficient since it will reallocate x each for step and it is not bulletproof (no error handling, no type checking): therefore it will fail if it encounters anything (matrix, string, row vector) but column vector which are likely to be found in such containers.
Anyway, it will ease a not-so-stringent-and-heuristic design, but please consider reimplementing when robust design is needed.
You can padding each cell with zeros, and align the lengths to the longest cell vector. It is done in a loop by iterating each cell vector.
This depends on whether the vectors in c are row or column vectors. But usually the fastest and most compact ways are:
c={[1 2 3], [4 5 6 7 8], [9 10]}
cell2mat(c)
cat(2, c{:})
or
c={[1 2 3]', [4 5 6 7 8]', [9 10]'}
% cell2mat(c) % Doesn't work.
cat(1, c{:})
so personally, I prefer cat.
In Matlab; without loops:
If the cell array contains column vectors and you want to arrange them into one big column vector:
result = vertcat(c{:}); %// vertically concat all vectors
Example:
>> c = {[1;2], [1;2;3]};
>> result = vertcat(c{:})
result =
1
2
1
2
3
If the cell array contains row vectors, you can arrange them as rows of a matrix, filling non-existent values with NaN (or any other value):
M = max(cellfun(#numel, c)); %// max length of vectors
c2 = cellfun(#(row)[row NaN(1,M-numel(row))], c, 'uni', 0); %// fill with NaN
result = vertcat(c2{:}); %// concat all equal-size row vectors into a matrix
Example:
>> c = {[1 2], [1 2 3]};
>> M = max(cellfun(#numel, c));
>> c2 = cellfun(#(row)[row NaN(1,M-numel(row))], c, 'uni', 0);
>> result = vertcat(c2{:})
result =
1 2 NaN
1 2 3

Vector as column index in matrix

Given a matrix A (mxn) and a vector B (mx1) I want to create a vector C (mx1) in which each row element is the row element of A from a column indexed by B.
Is it possible to do this, without using loops?
A = [1 2; 3 4; 5 6];
B = [2 1 1].';
Then I want:
C = [2 3 5].';
Convert the column subscripts of B to linear indices and then use them to reference elements in A:
idx = sub2ind(size(A), (1:size(A, 1)).', B);
C = A(idx);
(for more information, read the part about linear indexing in this answer).