Generate all possible combinations of the elements of some vectors (Cartesian product)

Solution 1:

Consider this solution using the NDGRID function:

sets = {[1 2], [1 2], [4 5]};
[x y z] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:)];

cartProd =
     1     1     4
     2     1     4
     1     2     4
     2     2     4
     1     1     5
     2     1     5
     1     2     5
     2     2     5

Or if you want a general solution for any number of sets (without having to create the variables manually), use this function definition:

function result = cartesianProduct(sets)
    c = cell(1, numel(sets));
    [c{:}] = ndgrid( sets{:} );
    result = cell2mat( cellfun(@(v)v(:), c, 'UniformOutput',false) );
end

Note that if you prefer, you can sort the results:

cartProd = sortrows(cartProd, 1:numel(sets));

Also, the code above does not check if the sets have no duplicate values (ex: {[1 1] [1 2] [4 5]}). Add this one line if you want to:

sets = cellfun(@unique, sets, 'UniformOutput',false);

Solution 2:

Try ALLCOMB function at FileExchange.

If you store you vectors in a cell array, you can run it like this:

a = {[1 2], [1 2], [4 5]};
allcomb(a{:})
ans =

     1     1     4
     1     1     5
     1     2     4
     1     2     5
     2     1     4
     2     1     5
     2     2     4
     2     2     5

Solution 3:

This late answers provides two additional solutions, where the second is the solution (in my opinion) and an improvement on Amro's answer solution with ndgrid by applying MATLAB's powerful comma-separated lists instead of cell arrays for high performance,

  1. If you have the Neural Network Toolbox: use combvec
  2. If you do not have the toolbox, as is usually the case: below is another way to generalize the Cartesian product for any number of sets.

Just as Amro did in his answer, the comma-separated lists syntax (v{:}) supplies both the inputs and outputs of ndgrid. The difference (fourth line) is that it avoids cellfun and cell2mat by applying comma-separated lists, again, now as the inputs to cat:

N = numel(a);
v = cell(N,1);
[v{:}] = ndgrid(a{:});
res = reshape(cat(N+1,v{:}),[],N);

The use of cat and reshape cuts execution time almost in half. This approach was demonstrated in my answer to an different question, and more formally by Luis Mendo.