Find row indices of different values ​​in a matrix

Having matrix A (n * 2) as source and B as a vector containing a subset of the elements of A, I would like to find the row index of the elements.

A=[1 2;1 3; 4 5];
B=[1 5];
F=arrayfun(@(x)(find(B(x)==A)),1:numel(B),'UniformOutput',false)

      

gives the following outputs in a cell according to this help page

[2x1 double]    [6]

      

specifying the indices of all cases in the column. But I would like to have row indices. those. I would like to know that item 1 happens on line 1 and line 2, and item 5 only happens on line 3. If the indices were across a number of rows, I could use ceil (F {x} / 2) to get the desired result. Now with a variable number of lines, what's your suggested solution? As it may be that there is no complete "rows" include tag in the ismember function, it does not work. Also, I would like to know all the indices of the specified items. Thanks in advance for any help.

+3


source to share


3 answers


Approach 1

To convert F

from the current linear-index form to index strings use mod

:

rows = cellfun(@(x) mod(x-1,size(A,1))+1, F, 'UniformOutput', false);

      

You can combine this with your code in one line. Also note that you can directly use B

as input arrayfun

and you will avoid one step of indexing:

rows = arrayfun(@(x) mod(find(x==A)-1,size(A,1))+1, B(:), 'UniformOutput', false);

      

How it works :

F

as indicated by your code is a linear index in the form of a column. This means that the index runs through the first column B

, starts at the top of the second column and goes down again, etc. Thus, the line number can only be obtained using the modulo ( mod

) operation .

Approach 2

Using bsxfun

and accumarray

:



t = any(bsxfun(@eq, B(:), reshape(A, 1, size(A,1), size(A,2))), 3); %// occurrence pattern
[ii, jj] = find(t); %// ii indicates an element of B, and jj is row of A where it occurs
rows = accumarray(ii, jj, [], @(x) {x}); %// group results according to ii

      

How it works :

Assuming A

and B

as in your example t

is a 2x3 matrix

t =
     1     1     0
     0     0     1

      

mth row t

contains 1

n in column if mth element from B

occurs in nth row B

. These values ​​are converted to row and column form with find

:

ii =
     1
     1
     2
jj =
     1
     2
     3

      

This means that the first item B

appears on lines 1 and 2 of A

; and the second is on line 3 B

.

Finally, the values jj

are grouped (c accumarray

) according to their respective value ii

to generate the desired result.

+3


source


One approach with bsxfun

and accumarray

-

%// Create a match of B in A with each column of matches representing the
%// rows in A where there is at least one match for each element in B 
matches = squeeze(any(bsxfun(@eq,A,permute(B(:),[3 2 1])),2))

%// Get the indices values and the corresponding IDs of B
[indices,B_id] = find(matches)
%// Or directly for performance:
%// [indices,B_id] = find(any(bsxfun(@eq,A,permute(B(:),[3 2 1])),2))

%// Accumulate the indices values using B_id as subscripts
out = accumarray(B_id(:),indices(:),[],@(x) {x})

      



Example run -

>> A
A =
     1     2
     1     3
     4     5
>> B
B =
     1     5
>> celldisp(out) %// To display the output, out
out{1} =
     1
     2
out{2} =
     3

      

+3


source


C arrayfun

, ismember

andfind

[r,c] = arrayfun(@(x) find(ismember(A,x)) , B, 'uni',0);

      

Where r

gives the results you want, you can also use a variable c

to get the column of each number inB

Sample injection results:

>> celldisp(r)

r{1} =
 1
 2

r{2} = 
 3


>> celldisp(c)

c{1} = 
 1
 1

c{2} =
 2

      

+1


source







All Articles