5

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?

Community
  • 1
  • 1
foglerit
  • 7,792
  • 8
  • 44
  • 64
  • 1
    You could use a solution that work for integers set and then think of the result (the combinations) as the indexes to your cell arrays. – Aabaz Dec 13 '11 at 16:18
  • 2
    Closely-related: [Matlab - Generate all possible combinations of the elements of some vectors](http://stackoverflow.com/q/4165859/52738), [MATLAB: Enumerating All Combinations of Items in An Arbitrary Number of Sets](http://stackoverflow.com/q/6607355/52738), [How can I create all combinations of characters in sets of text?](http://stackoverflow.com/q/5623120/52738). The first two deal with numeric vectors, and the third deals with character arrays, but the underlying solution is effectively the same for cell arrays. – gnovice Dec 13 '11 at 17:38

2 Answers2

6

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'
Community
  • 1
  • 1
gnovice
  • 125,304
  • 15
  • 256
  • 359
5

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'
Oli
  • 15,935
  • 7
  • 50
  • 66
  • Very simple and clean, I like it a lot. I accepted gnovice's answer for the generality, but your answer was very helpful to understand his. – foglerit Dec 13 '11 at 17:33