Search code examples
matlabfindrowcellindices

find row indices of different values in matrix


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

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]

indicating the indices of all occurrence in column-wise. But I'd like to have the indices of rows. i.e. I'd like to know that element 1 happens in row 1 and row 2 and element 5 happens just in row 3. If the indices were row-wise I could use ceil(F{x}/2) to have the desired output. Now with the variable number of rows, what's your suggested solution? As it may happens that there's no complete inclusion tag 'rows' in ismember function does not work. Besides, I'd like to know all indices of specified elements. Thanks in advance for any help.


Solution

  • Approach 1

    To convert F from its current linear-index form into row indices, use mod:

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

    You can combine this with your code into a single line. Note also that you can directly use B as an input to arrayfun, and you avoid one stage of indexing:

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

    How this works:

    F as given by your code is a linear index in column-major form. This means the index runs down the first column of B, the begins at the top of the second column and runs down again, etc. So the row number can be obtained with just a 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 this works:

    Assuming A and B as in your example, t is the 2x3 matrix

    t =
         1     1     0
         0     0     1
    

    The m-th row of t contains 1 at column n if the m-th element of B occurs at the n-th row of B. These values are converted into row and column form with find:

    ii =
         1
         1
         2
    jj =
         1
         2
         3
    

    This means the first element of B ocurrs at rows 1 and 2 of A; and the second occurs at row 3 of B.

    Lastly, the values of jj are grouped (with accumarray) according to their corresponding value of ii to generate the desired result.