Evan
Evan

Reputation: 207

Check if cell array is a subset of a nother in Matlab

I have two cell arrays of strings as follows

 A={{a,b},{c},{d,e}}
 B={{a,b},{c,d},{e}}

I want to check if A is a subset of B, meaning that each cell in A has a super-cell in B. In the given example it is not since A contains {d,e} while B does not have any cell that has those or more elements. I think ismember should be useful in this case, but I just could not write down the logic.

Thank you!

Upvotes: 5

Views: 1528

Answers (4)

Pursuit
Pursuit

Reputation: 12345

Given A and B

A={{'a','b'},{'c'},{'d','e'}}
B={{'a','b'},{'c','d'},{'e'}}

We can define a function isSubset, as follows:

isSubset = @(superSet,subSet)isempty(setdiff(subSet, superSet));

And test it:

isSubset(B{1}, A{1})  %true
isSubset(B{2}, A{2})  %true
isSubset(B{3}, A{3})  %false

Now we can use isSubSet and cellfun to define a function isSubSetOfAny, which checks to see if a particular subset is a subset of any of a set of sets, like this:

isSubSetOfAny = @(superSetSet, subSet) any(cellfun(@(x)isSubset(x, subSet), superSetSet));

And test it:

isSubSetOfAny(B, A{1})  %True
isSubSetOfAny(B, A{2})  %True
isSubSetOfAny(B, A{3})  %True

Now we can use isSubSetOfAny plus cellfun (again) to define isEachMemberASubsetOfAny, which performs the operation you describe:

    isEachMemberASubsetOfAny = @(superSetSet, subSetSet) all(cellfun(@(x)isSubSetOfAny(superSetSet, x), subSetSet));

And test it:

isEachMemberASubsetOfAny(B, A)    %Returns false

A_1 = {{'a','b'},{'c'},{'e'}};    %Define a variant of `A`
isEachMemberASubsetOfAny(B, A_1)  %Returns false

Upvotes: 7

nhowe
nhowe

Reputation: 929

What are the types of a, b, etc.? If they are strings, you can use setdiff to test whether one set is contained within another. Suitable use of cellfun and any or all should do it. Like so:

all(cellfun(@(a)any(cellfun(@(b)isempty(setdiff(a,b)),B)),A))

If they're some other type, you can make a simple m-file to check for a super-cell. Replace isempty(setdiff(a,b)) with a call to this function. It will have to loop through the elements of a and check for each one whether it exists in b.

Upvotes: 2

Dennis Jaheruddin
Dennis Jaheruddin

Reputation: 21563

Assuming a,b etc are strings you could do the following:

For each cell of A loop through B and see whether there is a cell in B for which all elements in the cell are member. Here is an example:

 A={{'abc','b'},{'c'},{'d','e'}};
 B={{'aabc','b'},{'c','d'},{'d','e'}}; %Remove the first a to return true


 subset = true;
 for i = 1:length(A)
     found = false; 
     for j = 1:length(B)
         found = found || all(ismember(A{i},B{j}));
     end
     subset = subset && found;
 end
 subset

Upvotes: 2

Amro
Amro

Reputation: 124563

How about something like:

function tf = is_subset(A,B)
    narginchk(2,2)
    assert(iscell(A) && all(cellfun(@iscellstr,A)));
    assert(iscell(B) && all(cellfun(@iscellstr,B)));

    for ia=1:numel(A)
        tf = false;
        for ib=1:numel(B)
            if all(ismember(A{ia},B{ib}));
                tf = true;
                break
            end
        end
        if ~tf
            break
        end
    end
end

With

[a,b,c,d,e] = deal('1','2','3','4','5');

A = {{a,b},{c},{d,e}};
B = {{a,b},{c,d},{e}};
is_subset(A,B)             %# false

B = {{a,b},{c,d,e},{e}};
is_subset(A,B)             %# true

Upvotes: 4

Related Questions