生成一些向量元素的所有可能组合(笛卡尔积)

时间:2010-11-12 14:56:42

标签: matlab combinatorics cartesian-product

我想生成给定数量向量的元素的所有可能组合。

例如,对于[1 2][1 2][4 5],我想要生成元素:

[1 1 4; 1 1 5; 1 2 4; 1 2 5; 2 1 4; 2 1 5; 2 2 4; 2 2 5]

问题是我不知道我需要计算组合的向量的数量。在这种情况下可能有3个,或者可能有10个,我需要泛化。你能帮我在MATLAB中帮助我吗?是否已有可以执行此任务的预定义功能?

4 个答案:

答案 0 :(得分:47)

使用NDGRID函数考虑此解决方案:

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

或者,如果您想要任意数量的集合的通用解决方案(无需手动创建变量),请使用此函数定义:

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

请注意,如果您愿意,可以对结果进行排序:

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

此外,上面的代码不会检查这些集合是否没有重复值(例如:{[1 1] [1 2] [4 5]})。如果您想要添加这一行:

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

答案 1 :(得分:16)

在FileExchange尝试ALLCOMB功能。

如果将向量存储在单元格数组中,则可以像下面这样运行:

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

答案 2 :(得分:11)

这个迟到的答案提供了两个额外的解决方案,其中第二个是解决方案(在我看来),并通过应用MATLAB强大的逗号分隔列表对Amro的答案解决方案进行了改进ndgrid而不是用于高性能的单元阵列,

  1. 如果您有神经网络工具箱:请使用combvec
  2. 如果你拥有工具箱,通常就是这种情况:下面是将笛卡尔积用于任意数量集的另一种方法。
  3. 正如Amro在答案中所做的那样,逗号分隔列表语法(v{:})提供ndgrid的输入和输出。差异(第四行)是通过应用以逗号分隔的列表来避免cellfuncell2mat,现在又作为cat的输入:

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

    catreshape的使用将执行时间减少了近一半。这种方法已在my answer to an different questionmore formally by Luis Mendo中得到证明。

答案 3 :(得分:0)

我们也可以在matlab中使用'combvec'指令

    no_inp=3 % number of inputs we want...in this case we have 3 inputs                  
    a=[1 2 3]
    b=[1 2 3]
    c=[1 2 3]

    pre_final=combvec(c,b,a)';
    final=zeros(size(pre_final));

    for i=1:no_inp
    final(:,i)=pre_final(:,no_inp-i+1);
    end
    final 

希望它有所帮助。 祝你好运。