枚举单元格组合

Enumerating combinations of cells

假设我有 3 个单元格:

M1={ [1,1,1], [2,2,2] }
M2={ [3,3], [4,4] }
M3={ [5], [6] }

我想获取 M1 中的每个元素,将其与 M2 中的每个元素组合,将其与 M3 中的每个元素组合,等等。

对于上面的输入,我想产生一个巨细胞,如:

[1,1,1],[3,3],[5]
[1,1,1],[3,3],[6]
[1,1,1],[4,4],[5]
[1,1,1],[4,4],[6]
[2,2,2],[3,3],[5]
[2,2,2],[3,3],[6]
[2,2,2],[4,4],[5]
[2,2,2],[4,4],[6]

我该怎么做?通常,单元格的数量 (M1,M2...Mn) 及其大小是未知的(并且在变化)。

这个函数可以满足您的需求:

function C = add_permutations(A,B)
% A is a cell array NxK, B is 1xM
% C is a cell array N*M x K+1
N = size(A,1);
A = reshape(A,N,1,[]);
C = cat(3,repmat(A,1,numel(B)),repmat(B,N,1));
C = reshape(C,[],size(C,3));

它通过在不同的维度上复制两个元胞数组来创建它们的所有组合,然后沿着第三个维度连接并折叠前两个维度。因为我们要用不同的元胞数组重复调用,输入A(NxK)每行有K个矩阵,这些是前面的组合。 B是一个元胞向量,每个元素将与A的每一行相结合。

您使用方法如下:

M1 = { 'a', 'b', 'c', 'd' }; % These are easier for debugging than OP's input, but cell elements can be anything at all.
M2 = { 1, 2 };
M3 = { 10, 12 };

X = M1.';
X = add_permutations(X,M2);
X = add_permutations(X,M3);

X 现在包含:

X =

  16×3 cell array

    'a'    [1]    [10]
    'b'    [1]    [10]
    'c'    [1]    [10]
    'd'    [1]    [10]
    'a'    [2]    [10]
    'b'    [2]    [10]
    'c'    [2]    [10]
    'd'    [2]    [10]
    'a'    [1]    [12]
    'b'    [1]    [12]
    'c'    [1]    [12]
    'd'    [1]    [12]
    'a'    [2]    [12]
    'b'    [2]    [12]
    'c'    [2]    [12]
    'd'    [2]    [12]

这不是排列,而是枚举:你有 3 个符号,每个符号有 2 个可能的值,你只是简单地枚举所有可能的值 "numbers"。您可以像计算 3 位数的二进制数一样考虑它。

在这种情况下,枚举所有这些可能性的一种方法是使用 ndgrid。如果 M1n1 个元素,M2n2 个元素,等等:

n1 = numel(M1);
n2 = numel(M2);
n3 = numel(M3);

[a,b,c] = ndgrid(1:n1, 1:n2, 1:n3);

这里a,b,c是每一个3维数组,代表了"grid"种组合。显然你不需要那个,所以你可以对它们进行矢量化,并使用它们来创建 M1, M2, M3 中各种元素的组合,就像这样

vertcat( M1(a(:)), M2(b(:)), M3(c(:)) )

如果您有兴趣将此概括为任意数量的 M,也可以这样做,但请记住,随着维度的增加,这些 "grids" 的增长速度非常快。

注: vertcat代表"vertical concatenation",之所以是竖的而不是横的,是因为M1(a(:))的结果是行形单元格,即使 a(:) 是列向量。这只是令人头疼的索引问题,但如果需要,您可以简单地转置结果 Nx3.