Cartesian product in MATLAB
Asked Answered
O

3

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?

Oleoresin answered 23/3, 2012 at 4:41 Comment(3)
Actually, I found that mathworks.com/matlabcentral/fileexchange/5898 this thing does exactly what I want!Oleoresin
You should put that as an answer and accept your own answer to close the question.Rockingham
Similar question: Matlab - Generate all possible combinations of the elements of some vectorsCulberson
C
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
Capful answered 23/3, 2012 at 9:11 Comment(3)
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.Hepcat
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!Capful
You're entirely correct on that one. I'll correct his post for clarity.Hepcat
F
6

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
Foregather answered 22/10, 2015 at 14:26 Comment(0)
D
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
Disgust answered 28/4, 2021 at 23:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.