如何获得矩阵中元素的所有可能组合,但不允许在列之间交换元素?
How to get all the possible combinations of elements in a matrix, but don't allow exchange of elements inbetween columns?
假设我有这个矩阵 A:[3 x 4]
1 4 7 10
2 5 8 11
3 6 9 12
我想置换每列中的元素,但它们不能更改为不同的列,因此 1 2 3
需要始终是第一列的一部分。例如我想要:
3 4 8 10
1 5 7 11
2 6 9 12
3 4 8 11
1 6 7 10
2 5 9 12
1 6 9 11
. . . .
所以在一个矩阵中我想要所有可能的排列,在这种情况下,有 3 个不同的选择 3x3x3x3=81
possibilities.So 我的结果矩阵应该是 81x4
,因为我每次只需要一个[1x4]
线向量答案,那81次。
另一种解决问题的方法是(对我来说也是一样),如果我有 4 列向量:
a=[1;2;3]
b=[4;5;6]
c=[7;8;9]
d=[10;11;12;13]
与我之前的例子相比,每个列向量可以有不同的行数。然后就像我有 4 个盒子,A,B C,D,我只能将 a 的一个元素放在 A 中,b 放在 B 中,依此类推;所以我想得到所有可能的排列,答案 [A B C D]
是 [1x4]
行,在这种情况下,我会有 3x3x3x4=108
不同的行。所以我被误解的地方(我的错)是我不想要所有不同的 [3x4] 矩阵答案,而只想要 [1x4] 行。
所以在这种情况下答案是:
1 4 7 10
and 1 4 7 11
and 1 4 7 12
and 1 4 7 13
and 2 4 8 10
and ...
until there are the 108 combinations
Matlab 中的函数 perms
不能这样做,因为我不想置换所有矩阵(顺便说一句,这已经是一个太大的矩阵了)。
那么你知道我该怎么做吗?或者是否有一个功能可以做到这一点?当然,我也可以有不同大小的矩阵。谢谢
这有点复杂,但不需要任何额外的工具箱就可以工作:
你基本上想要一个 b
元素 'truth table' 如果你将它应用到每个元素,你可以像这样生成 (adapted from here):
[b, n] = size(A)
truthtable = dec2base(0:power(b,n)-1, b) - '0'
现在您需要通过将列数乘以总行数将事实 table 转换为线性索引:
idx = bsxfun(@plus, b*(0:n-1)+1, truthtable)
现在您不是将这个真理 table 应用到每个元素,而是将它应用到每个排列。有 6
个排列,因此 b
变为 6
。诀窍是创建一个 6
-by-1
元胞数组,其中每个元素都有不同的 [1,2,3]
排列,然后将真理 table 的想法应用到那个:
[m,n] = size(A);
b = factorial(m);
permutations = reshape(perms(1:m)',[],1);
permCell = mat2cell(permutations,ones(b,1)*m,1);
truthtable = dec2base(0:power(b,n)-1, b) - '0';
expandedTT = cell2mat(permCell(truthtable + 1));
idx = bsxfun(@plus, m*(0:n-1), expandedTT);
A(idx)
你的问题似乎是一个非常有趣的脑筋急转弯。我建议如下:
in = [1,2,3;4,5,6;7,8,9;10,11,12]';
b = perms(1:3);
a = 1:size(b,1);
c = combvec(a,a,a,a);
for k = 1:length(c(1,:))
out{k} = [in(b(c(1,k),:),1),in(b(c(2,k),:),2),in(b(c(3,k),:),3),in(b(c(4,k),:),4)];
end
%and if you want your result as an ordinary array:
out = vertcat(out{:});
b
是一个 6x3
数组,其中包含 [1,2,3]
所有可能的排列。 c
是 4x1296
数组,包含 a = 1:6
中元素的所有可能组合。在 for 循环中,我们使用从 1 到 6 的数字来获得 b
中的排列,并且该排列用作列的索引。
希望对您有所帮助
另一个答案。相当具体只是为了演示这个概念,但可以很容易地进行调整。
A = [1,4,7,10;2,5,8,11;3,6,9,12];
P = perms(1:3)'
[X,Y,Z,W] = ndgrid(1:6,1:6,1:6,1:6);
您现在有 1296 个排列。如果您想访问第 400 个:
Permutation_within_column = [P(:,X(400)), P(:,Y(400)), P(:,Z(400)), P(:,W(400))];
ColumnOffset = repmat([0:3]*3,[3,1])
My_permutation = Permutation_within_column + ColumnOffset; % results in valid linear indices
A(My_permutation)
这种方法可以让你按需获得第400个排列;如果您希望将所有可能的排列连接到第 3 维(即 3x4x1296 矩阵),您可以使用 for
循环执行此操作,或者简单地调整上述内容并进行矢量化;例如,如果您想创建一个 3x4x2 矩阵,其中包含沿第 3 维的前两个排列:
Permutations_within_columns = reshape(P(:,X(1:2)),3,1,[]);
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,Y(1:2)),3,1,[]));
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,Z(1:2)),3,1,[]));
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,W(1:2)),3,1,[]));
ColumnOffsets = repmat([0:3]*3,[3,1,2]);
My_permutations = Permutations_within_columns + ColumnOffsets;
A(My_permutations)
这种方法使您能够收集特定的子范围,如果可用内存是一个问题(即对于较大的矩阵)并且您更愿意执行操作,这可能很有用按块。如果内存不是问题,您可以根据需要在一个巨大的矩阵中一次获得所有 1296 个排列;适当调整(例如,在第 3 维中将 ColumnOffsets 复制正确的次数)
基本上您想要获得 1:3
排列的 4 倍的所有组合。
您可以使用神经网络工具箱中的 combvec
生成这些 (), or with permn from the File Exchange.
之后是管理索引、应用 sub2ind(使用正确的列索引)并重新排列直到一切都按您想要的顺序排列的问题。
a = [1 4 7 10
2 5 8 11
3 6 9 12];
siz = size(a);
perm1 = perms(1:siz(1));
Nperm1 = size(perm1,1); % = factorial(siz(1))
perm2 = permn(1:Nperm1, siz(2) );
Nperm2 = size(perm2,1);
permidx = reshape(perm1(perm2,:)', [Nperm2 siz(1), siz(2)]); % reshape unnecessary, easier for debugging
col_base_idx = 1:siz(2);
col_idx = col_base_idx(ones(Nperm2*siz(1) ,1),:);
lin_idx = reshape(sub2ind(size(a), permidx(:), col_idx(:)), [Nperm2*siz(1) siz(2)]);
result = a(lin_idx);
这避免了任何循环或单元格连接,而是使用直接索引。
每列排列,唯一行
同样的方法:
siz = size(a);
permidx = permn(1:siz(1), siz(2) );
Npermidx = size(permidx, 1);
col_base_idx = 1:siz(2);
col_idx = col_base_idx(ones(Npermidx, 1),:);
lin_idx = reshape(sub2ind(size(a), permidx(:), col_idx(:)), [Npermidx siz(2)]);
result = a(lin_idx);
这是另一个八度友好的解决方案:
function result = Tuples(A)
[P,n]= size(A);
M = reshape(repmat(1:P, 1, P ^(n-1)), repmat(P, 1, n));
result = zeros(P^ n, n);
for i = 1:n
result(:, i) = A(reshape(permute(M, circshift((1:n)', i)), P ^ n, 1), i);
end
end
%%%example
A = [...
1 4 7 10;...
2 5 8 11;...
3 6 9 12];
result = Tuples(A)
更新:
问题更新为:给定 n 个不同长度的向量生成所有可能元组的列表,其第 i 个元素来自向量 i:
function result = Tuples( A)
if exist('repelem') ==0
repelem = @(v,n) repelems(v,[1:numel(v);n]);
end
n = numel(A);
siz = [ cell2mat(cellfun(@numel, A , 'UniformOutput', false))];
tot_prd = prod(siz);
cum_prd=cumprod(siz);
tot_cum = tot_prd ./ cum_prd;
cum_siz = cum_prd ./ siz;
result = zeros(tot_prd, n);
for i = 1: n
result(:, i) = repmat(repelem(A{i},repmat(tot_cum(i),1,siz(i))) ,1,cum_siz(i));
end
end
%%%%example
a = {...
[1;2;3],...
[4;5;6],...
[7;8;9],...
[10;11;12;13]...
};
result =Tuples(a)
假设我有这个矩阵 A:[3 x 4]
1 4 7 10
2 5 8 11
3 6 9 12
我想置换每列中的元素,但它们不能更改为不同的列,因此 1 2 3
需要始终是第一列的一部分。例如我想要:
3 4 8 10
1 5 7 11
2 6 9 12
3 4 8 11
1 6 7 10
2 5 9 12
1 6 9 11
. . . .
所以在一个矩阵中我想要所有可能的排列,在这种情况下,有 3 个不同的选择 3x3x3x3=81
possibilities.So 我的结果矩阵应该是 81x4
,因为我每次只需要一个[1x4]
线向量答案,那81次。
另一种解决问题的方法是(对我来说也是一样),如果我有 4 列向量:
a=[1;2;3]
b=[4;5;6]
c=[7;8;9]
d=[10;11;12;13]
与我之前的例子相比,每个列向量可以有不同的行数。然后就像我有 4 个盒子,A,B C,D,我只能将 a 的一个元素放在 A 中,b 放在 B 中,依此类推;所以我想得到所有可能的排列,答案 [A B C D]
是 [1x4]
行,在这种情况下,我会有 3x3x3x4=108
不同的行。所以我被误解的地方(我的错)是我不想要所有不同的 [3x4] 矩阵答案,而只想要 [1x4] 行。
所以在这种情况下答案是:
1 4 7 10
and 1 4 7 11
and 1 4 7 12
and 1 4 7 13
and 2 4 8 10
and ...
until there are the 108 combinations
Matlab 中的函数 perms
不能这样做,因为我不想置换所有矩阵(顺便说一句,这已经是一个太大的矩阵了)。
那么你知道我该怎么做吗?或者是否有一个功能可以做到这一点?当然,我也可以有不同大小的矩阵。谢谢
这有点复杂,但不需要任何额外的工具箱就可以工作:
你基本上想要一个 b
元素 'truth table' 如果你将它应用到每个元素,你可以像这样生成 (adapted from here):
[b, n] = size(A)
truthtable = dec2base(0:power(b,n)-1, b) - '0'
现在您需要通过将列数乘以总行数将事实 table 转换为线性索引:
idx = bsxfun(@plus, b*(0:n-1)+1, truthtable)
现在您不是将这个真理 table 应用到每个元素,而是将它应用到每个排列。有 6
个排列,因此 b
变为 6
。诀窍是创建一个 6
-by-1
元胞数组,其中每个元素都有不同的 [1,2,3]
排列,然后将真理 table 的想法应用到那个:
[m,n] = size(A);
b = factorial(m);
permutations = reshape(perms(1:m)',[],1);
permCell = mat2cell(permutations,ones(b,1)*m,1);
truthtable = dec2base(0:power(b,n)-1, b) - '0';
expandedTT = cell2mat(permCell(truthtable + 1));
idx = bsxfun(@plus, m*(0:n-1), expandedTT);
A(idx)
你的问题似乎是一个非常有趣的脑筋急转弯。我建议如下:
in = [1,2,3;4,5,6;7,8,9;10,11,12]';
b = perms(1:3);
a = 1:size(b,1);
c = combvec(a,a,a,a);
for k = 1:length(c(1,:))
out{k} = [in(b(c(1,k),:),1),in(b(c(2,k),:),2),in(b(c(3,k),:),3),in(b(c(4,k),:),4)];
end
%and if you want your result as an ordinary array:
out = vertcat(out{:});
b
是一个 6x3
数组,其中包含 [1,2,3]
所有可能的排列。 c
是 4x1296
数组,包含 a = 1:6
中元素的所有可能组合。在 for 循环中,我们使用从 1 到 6 的数字来获得 b
中的排列,并且该排列用作列的索引。
希望对您有所帮助
另一个答案。相当具体只是为了演示这个概念,但可以很容易地进行调整。
A = [1,4,7,10;2,5,8,11;3,6,9,12];
P = perms(1:3)'
[X,Y,Z,W] = ndgrid(1:6,1:6,1:6,1:6);
您现在有 1296 个排列。如果您想访问第 400 个:
Permutation_within_column = [P(:,X(400)), P(:,Y(400)), P(:,Z(400)), P(:,W(400))];
ColumnOffset = repmat([0:3]*3,[3,1])
My_permutation = Permutation_within_column + ColumnOffset; % results in valid linear indices
A(My_permutation)
这种方法可以让你按需获得第400个排列;如果您希望将所有可能的排列连接到第 3 维(即 3x4x1296 矩阵),您可以使用 for
循环执行此操作,或者简单地调整上述内容并进行矢量化;例如,如果您想创建一个 3x4x2 矩阵,其中包含沿第 3 维的前两个排列:
Permutations_within_columns = reshape(P(:,X(1:2)),3,1,[]);
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,Y(1:2)),3,1,[]));
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,Z(1:2)),3,1,[]));
Permutations_within_columns = cat(2, Permutations_within_columns, reshape(P(:,W(1:2)),3,1,[]));
ColumnOffsets = repmat([0:3]*3,[3,1,2]);
My_permutations = Permutations_within_columns + ColumnOffsets;
A(My_permutations)
这种方法使您能够收集特定的子范围,如果可用内存是一个问题(即对于较大的矩阵)并且您更愿意执行操作,这可能很有用按块。如果内存不是问题,您可以根据需要在一个巨大的矩阵中一次获得所有 1296 个排列;适当调整(例如,在第 3 维中将 ColumnOffsets 复制正确的次数)
基本上您想要获得 1:3
排列的 4 倍的所有组合。
您可以使用神经网络工具箱中的 combvec
生成这些 (
之后是管理索引、应用 sub2ind(使用正确的列索引)并重新排列直到一切都按您想要的顺序排列的问题。
a = [1 4 7 10
2 5 8 11
3 6 9 12];
siz = size(a);
perm1 = perms(1:siz(1));
Nperm1 = size(perm1,1); % = factorial(siz(1))
perm2 = permn(1:Nperm1, siz(2) );
Nperm2 = size(perm2,1);
permidx = reshape(perm1(perm2,:)', [Nperm2 siz(1), siz(2)]); % reshape unnecessary, easier for debugging
col_base_idx = 1:siz(2);
col_idx = col_base_idx(ones(Nperm2*siz(1) ,1),:);
lin_idx = reshape(sub2ind(size(a), permidx(:), col_idx(:)), [Nperm2*siz(1) siz(2)]);
result = a(lin_idx);
这避免了任何循环或单元格连接,而是使用直接索引。
每列排列,唯一行
同样的方法:
siz = size(a);
permidx = permn(1:siz(1), siz(2) );
Npermidx = size(permidx, 1);
col_base_idx = 1:siz(2);
col_idx = col_base_idx(ones(Npermidx, 1),:);
lin_idx = reshape(sub2ind(size(a), permidx(:), col_idx(:)), [Npermidx siz(2)]);
result = a(lin_idx);
这是另一个八度友好的解决方案:
function result = Tuples(A)
[P,n]= size(A);
M = reshape(repmat(1:P, 1, P ^(n-1)), repmat(P, 1, n));
result = zeros(P^ n, n);
for i = 1:n
result(:, i) = A(reshape(permute(M, circshift((1:n)', i)), P ^ n, 1), i);
end
end
%%%example
A = [...
1 4 7 10;...
2 5 8 11;...
3 6 9 12];
result = Tuples(A)
更新: 问题更新为:给定 n 个不同长度的向量生成所有可能元组的列表,其第 i 个元素来自向量 i:
function result = Tuples( A)
if exist('repelem') ==0
repelem = @(v,n) repelems(v,[1:numel(v);n]);
end
n = numel(A);
siz = [ cell2mat(cellfun(@numel, A , 'UniformOutput', false))];
tot_prd = prod(siz);
cum_prd=cumprod(siz);
tot_cum = tot_prd ./ cum_prd;
cum_siz = cum_prd ./ siz;
result = zeros(tot_prd, n);
for i = 1: n
result(:, i) = repmat(repelem(A{i},repmat(tot_cum(i),1,siz(i))) ,1,cum_siz(i));
end
end
%%%%example
a = {...
[1;2;3],...
[4;5;6],...
[7;8;9],...
[10;11;12;13]...
};
result =Tuples(a)