Search code examples
arraysmatlabmatrixcell-array

find array elements that match one of multiple conditions, sorted by condition matched


I have an m-by-n matrix (n > 3) where the two first columns have a lot of repetition of values. I have another two vectors, call them uniqueCol1 and uniqueCol2, which contain all the possible values for the two columns.

I want to find all the sub-matrices, which will be p-by-n (p =< m), where the two first columns match given values in uniqueCol1 and uniqueCol2. There is up to length(uniqueCol1) * length(uniqueCol2) such sub-matrices.

I could use ismember() to help find these sub-matrices, but I can't see a way of doing this where I would know what parts of the output matched what condition.

Alternatively I can do a for loop, as shown below, but this is extremely slow. Is there a way of vectorizing the below? I imagine the solution would have as output a cell array of these sub-matrices, as each sub-matrix is not generally the same size (so a multi-dimensional array would not work).

myBigMatrix = round(wgn(1000,6,1) * 3);
uniqueCol1 = unique(myBigMatrix(:,1));
uniqueCol2 = unique(myBigMatrix(:,2));
for i = 1:length(uniqueCol1)
    for j = 1:length(uniqueCol2)
        mySubMatrix = myBigMatrix( ...
            myBigMatrix(:,1) == uniqueCol1(i) & ...
            myBigMatrix(:,2) == uniqueCol2(j) , :);
        % then do something with mySubMatrix, 
        % as it's clear from i and j what condition it matched
    end
end

Solution

  • You can use the powerful accumarray function for this task:

    [uniqueCol1, ~, u1] = unique(myBigMatrix(:,1));
    [uniqueCol2, ~, u2] = unique(myBigMatrix(:,2));
    R = accumarray([u1 u2], (1:size(myBigMatrix,1)).', [], @(x) {myBigMatrix(sort(x),:)})
    

    Then R{m,n} contains the submatrix that matches the m-th element of uniqueCol1 and the n-th element of uniqueCol2.

    Example:

    myBigMatrix =
         3     5     3
         3     2     2
         3     5     1
         3     2     1
         1     5     4
         4     3     4
    

    gives

    >> uniqueCol1.'
    ans =
         1     3     4
    >> uniqueCol2.'
    ans =
         2     3     5
    
    >> R
    R = 
                  []              []    [1x3 double]
        [2x3 double]              []    [2x3 double]
                  []    [1x3 double]              []
    
    >> R{2,1} %// submatrix corresponding to 3 in first col and 2 in second col
    ans =
         3     2     2
         3     2     1
    
    >> R{3,2} %// submatrix corresponding to 4 in first col and 3 in second col
    ans =
         4     3     4