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

34

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

例如,对于[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中帮助我完成这个任务?是否已经有预定义的函数可以执行此任务?


10
你要找的东西叫做向量的“笛卡尔积”。你可以尝试在谷歌上搜索相关内容。 - High Performance Mark
5个回答

52

考虑使用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);

17

请在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

6
请注意,“ALLCOMB”使用了与Amro答案中基本相同的“NDGRID”方式,但具有更强的错误防护功能。 - lodhb

14

这篇晚回答提供了两个额外的解决方案,其中第二个是我认为更好的解决方案,并且使用MATLAB强大的逗号分隔列表而不是单元数组以获得高性能的Amro答案解决方案的改进。

  1. 如果您有神经网络工具箱:使用combvec
  2. 如果您没有该工具箱,通常如此:以下是另一种针对任意数量集合的笛卡尔积泛化的方法。

与Amro在他的答案中所做的一样,逗号分隔的列表语法(v{:})提供了ndgrid函数的输入和输出。区别(第四行)在于它通过再次应用逗号分隔的列表作为cat函数的输入来避免cellfuncell2mat函数:

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

使用 catreshape 几乎可以将执行时间缩短一半。在 我的另一个回答 中演示了这种方法,并且 由Luis Mendo更正式地进行了展示


在我看来,这是正确的方法。请注意,可以轻松地扩展它以获取长度为n的向量的长度为m的所有排列:[v {1:m}] = ndgrid(1:n);res = reshape(cat(m + 1,v {:}),[],m) - obchardon

1
自从MATLAB 2023a版本以后,你可以使用combinations函数,该函数支持向量、矩阵、单元数组以及它们的混合使用。
>> combinations([1 2], [1 2], [4 5])

ans =

  8×3 table

    Var1    Var2    Var3
    ____    ____    ____

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

输出以表格的形式呈现,支持混合类型。如果您的输出只需要单一类型,您可以使用table2array将输出转换为矩阵:
>> table2array(combinations([1 2], [1 2], [4 5]))

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

就我所知,我已经编写了一个模拟旧版本MATLAB(包括2013b版本)中combinations行为的适配器,并且支持混合类型。
function grid = combinations(varargin)
    grid = cell(nargin, 1);
    [grid{:}] = ndgrid(varargin{:});

    combos = cellfun(@(it) it(:), grid, 'UniformOutput', false)';
    combos = table(combos{:});
end

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 

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接