21

Here is the simplified version of the problem I have. Suppose I have a vector

p=[1 5 10] 

and another one

q=[.75 .85 .95]

And I want to come up with the following matrix:

res=[1, .75;
     1, .85;
     1, .95;
     5, .75;
     5, .85;
     5, .95;
    10, .75;
    10, .85;
    10, .95]

This is also known as the Cartesian Product. How can I do that?

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
emper
  • 401
  • 1
  • 7
  • 14
  • Actually, I found that http://www.mathworks.com/matlabcentral/fileexchange/5898 this thing does exactly what I want! – emper Mar 23 '12 at 04:54
  • 6
    You should put that as an answer and accept your own answer to close the question. – learnvst Mar 23 '12 at 05:48
  • Similar question: [Matlab - Generate all possible combinations of the elements of some vectors](http://stackoverflow.com/q/4165859/97160) – Amro Jul 26 '12 at 01:39

3 Answers3

48

Here's one way:

[X,Y] = meshgrid(p,q);
result = [X(:) Y(:)];

The output is:

result =

    1.0000    0.7500
    1.0000    0.8500
    1.0000    0.9500
    5.0000    0.7500
    5.0000    0.8500
    5.0000    0.9500
   10.0000    0.7500
   10.0000    0.8500
   10.0000    0.9500
nibot
  • 14,428
  • 8
  • 54
  • 58
  • While this indeed is the Cartesian Product, it's not what the OP asked for. It would need an aditional step of `result=sum(result,2)` to qualify. – jpjacobs Mar 23 '12 at 10:09
  • 4
    I don't think that's true. If you look closely, the result matrix in the OP's question appears to be 2×9, not 1×9. The first row is "1, 0.75" (note the space in "1 .75"), not 1.75. This is further confirmed by the linked FileExchange script that he says does exactly the right thing. I agree that it's confusing--I had to squint to see what was going on! – nibot Mar 23 '12 at 10:14
  • You're entirely correct on that one. I'll correct his post for clarity. – jpjacobs Mar 23 '12 at 10:18
5

A similar approach as the one described by @nibot can be found in matlab central file-exchange.

It generalizes the solution to any number of input sets. This would be a simplified version of the code:

function C = cartesian(varargin)
    args = varargin;
    n = nargin;

    [F{1:n}] = ndgrid(args{:});

    for i=n:-1:1
        G(:,i) = F{i}(:);
    end

    C = unique(G , 'rows');
end

For instance:

cartesian(['c','d','e'],[1,2],[50,70])

ans =

    99     1    50
    99     1    70
    99     2    50
    99     2    70
   100     1    50
   100     1    70
   100     2    50
   100     2    70
   101     1    50
   101     1    70
   101     2    50
   101     2    70
jruizaranguren
  • 12,679
  • 7
  • 55
  • 73
2

Here's a function, cartesian_product, that can handle any type of input, including string arrays, and returns a table with column names that match the names of the input variables. Inputs that are not variables are given names like var1, var2, etc.

function tbl = cartesian_product(varargin)
    names = arrayfun(@inputname, 1:nargin, 'UniformOutput', false);
    
    for i = 1:nargin
        if isempty(names{i})
            names{i} = ['var' num2str(i)];
        end
    end
    
    rev_args = flip(varargin);
    
    [A{1:nargin}] = ndgrid(rev_args{:});

    B = cellfun(@(x) x(:), A, 'UniformOutput', false);
    C = flip(B);
    
    tbl = table(C{:}, 'VariableNames', names);
end
>> x = ["a" "b"];
>> y = 1:3;
>> z = 4:5;
>> cartesian_product(x, y, z)

ans =

  12×3 table

     x     y    z
    ___    _    _

    "a"    1    4
    "a"    1    5
    "a"    2    4
    "a"    2    5
    "a"    3    4
    "a"    3    5
    "b"    1    4
    "b"    1    5
    "b"    2    4
    "b"    2    5
    "b"    3    4
    "b"    3    5
>> cartesian_product(1:2, 3:4)

ans =

  4×2 table

    var1    var2
    ____    ____

     1       3  
     1       4  
     2       3  
     2       4
Cameron Bieganek
  • 7,208
  • 1
  • 23
  • 40