枚举单元格组合
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
(N
xK
)每行有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
。如果 M1
有 n1
个元素,M2
有 n2
个元素,等等:
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
.
假设我有 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
(N
xK
)每行有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
。如果 M1
有 n1
个元素,M2
有 n2
个元素,等等:
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
.