TimeIsNear
TimeIsNear

Reputation: 755

Matlab - Return only rows of a matrix 'A' that not contain in other matrix 'B'

How do I return only the rows of a matrix 'A' that not contain some values (These values ​​are an array 'B')?

  A = {'A1',  5  'P01,P02,P03,P04'; 
        'A2'  7,  'P08,P09';
        'A3'  8,  'P07';
        'A4'  8,  'P10,P11'};

    B = { 'P07'; 'P10'; 'P11'};

I need to return only:

'A1'
'A2'

Thanks in advance for your help

Upvotes: 1

Views: 156

Answers (3)

Luis Mendo
Luis Mendo

Reputation: 112679

To remove rows of A which contain at least one of the strings in B

Fancy one-liner with two nested cellfuns and strfind at its core:

A(all(cell2mat(cellfun(@(b) cellfun(@isempty, strfind(A(:,end),b)).',B, 'uni', 0))),1)

Perhaps the logical indices computed as intermediate result are of interest:

ind = cell2mat(cellfun(@(b) cellfun(@isempty, strfind(A(:,end),b)).',B, 'uni', 0));
A(all(ind),1)

Namely, ~ind tells you which strings of B are contained in which rows of A . In the example,

>> ~ind
ans =
     0     0     1     0
     0     0     0     1
     0     0     0     1

How it works: strfind tests if each string of B is in A, and returns a vector with the corresponding positions. So an empty vector means the string is not present. If that vector is empty for all strings of B, that row of A should be selected.

Upvotes: 3

Rody Oldenhuis
Rody Oldenhuis

Reputation: 38032

Variations on Luis' theme:

ind = A( all(cellfun('isempty', ...
    cellfun(@strfind, ...
        repmat(A(:,end), 1,size(B,1)), ...
        repmat(B', size(A,1),1), 'UniformOutput', false)), 2), 1)

Somewhat against my own expectations, this is a LOT faster than Luis' solution. I think it is primarily due to the string function vs. anonymous function (cellfun is a lot faster with string functions than with anonymous functions). cell2mat not being built-in is also a factor.

Upvotes: 2

Dan
Dan

Reputation: 45752

I suggest you change the way you store the data in A as follows:

A = {'A1',  5,  {'P01','P02','P03','P04'}; 
     'A2',  7,  {'P08','P09'};
     'A3',  8,  {'P07'};
     'A4',  8,  {'P10','P11'}};

B = {'P07'; 'P10'; 'P11'};

Then you can do:

for n = 1:size(A,1)
    ind(n) = ~sum(ismember(B,A{n,3}));
end

A(ind,1)

Or if you prefer a one liner then:

A(cellfun(@(x)(~sum(ismember(B,x))), A(:,3)),1)

Upvotes: 1

Related Questions