Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MATLAB: Combinations of an arbitrary number of cell arrays

Is there a command or one-line strategy in MATLAB that will return all the combinations of the components of n cell arrays, taken n at a time?

An example of what I want to accomplish:

A = {'a1','a2'};
B = {'b1','b2','b3'};
C = combinations(A,B)
C = {'a1','b1' ;
     'a1','b2' ;
     'a1','b3' ;
     'a2','b1' ;
     'a2','b2' ;
     ... }

The command would be able to accept an arbitrary number of arguments and the result in the example would have as many columns as there are arguments to the function. (Of course, the syntax above is just meant for illustration and any method that would generate the results whatever the format would fit the bill)

EDIT: Similar questions have been asked for matrices instead of cells, e.g. link. Many solutions point to the FEX submission allcomb, but all such solutions are just wrappers around ndgrid, which only work with doubles. Any suggestions for non numeric sets?

like image 652
foglerit Avatar asked Dec 13 '11 16:12

foglerit


2 Answers

Although I address this in my answer to a related/near duplicate question, I'm posting a different version of my solution here since it appears you want a generalized solution, and my other answer is specific for the case of three input sets. Here's a function that should do what you want for any number of cell array inputs:

function combMat = allcombs(varargin)
  sizeVec = cellfun('prodofsize', varargin);
  indices = fliplr(arrayfun(@(n) {1:n}, sizeVec));
  [indices{:}] = ndgrid(indices{:});
  combMat = cellfun(@(c,i) {reshape(c(i(:)), [], 1)}, ...
                    varargin, fliplr(indices));
  combMat = [combMat{:}];
end

And here's how you would call it:

>> combMat = allcombs(A, B)

combMat = 

    'a1'    'b1'
    'a1'    'b2'
    'a1'    'b3'
    'a2'    'b1'
    'a2'    'b2'
    'a2'    'b3'
like image 153
gnovice Avatar answered Sep 28 '22 00:09

gnovice


A 2-line strategy:

 A = {'a1','a2'};
 B = {'b1','b2','b3'};

[a b]=ndgrid(1:numel(A),1:numel(B));
C= [A(a(:))' B(b(:))']

C = 
    'a1'    'b1'
    'a2'    'b1'
    'a1'    'b2'
    'a2'    'b2'
    'a1'    'b3'
    'a2'    'b3'
like image 31
Oli Avatar answered Sep 27 '22 22:09

Oli