返回可能重复的数组元素

时间:2017-03-15 12:10:23

标签: arrays matlab permutation combinatorics built-in

假设我有一个长度NM个不同对象(M < N)的数组,以便其中一些对象重复N_i ... N_M次。我想找到这些数组元素的所有可能的唯一处置(比如,排列),而不事先计算整个排列列表(包括时间和内存约束)。

当然,天真的解决方案是使用perms生成所有可能的排列,然后选择唯一的排列:

A = [1, 1, 2];

all_perms = perms(A)
    % all_perms =

    % 2     1     1
    % 2     1     1
    % 1     2     1
    % 1     1     2
    % 1     2     1
    % 1     1     2

unique_perms = unique(all_perms, 'rows')
    % unique_perms =

    % 1     1     2
    % 1     2     1
    % 2     1     1

但这会生成所有 N!排列,而不仅仅是N! / (N_1! * N_2! * ... * N_M!)。对于N = 3,这不会对内存消耗和时序产生太大影响,但随着N的增加和唯一元素的数量减少,差异可能会很大。所以:

是否有(希望是内置的)方法列出包含非不同对象的数组的所有唯一排列,而不是中间保留所有排列?

1 个答案:

答案 0 :(得分:3)

以下是Bruno Luong针对此问题在2014年建议的代码:

function p = uperm(a)
[u, ~, J] = unique(a);
p = u(up(J, length(a)));
end % uperm

function p = up(J, n)
ktab = histc(J,1:max(J));
l = n;
p = zeros(1, n);
s = 1;
for i=1:length(ktab)
    k = ktab(i);
    c = nchoosek(1:l, k);
    m = size(c,1);
    [t, ~] = find(~p.');
    t = reshape(t, [], s);
    c = t(c,:)';
    s = s*m;
    r = repmat((1:s)',[1 k]);
    q = accumarray([r(:) c(:)], i, [s n]);
    p = repmat(p, [m 1]) + q;
    l = l - k;
end
end

nchoosek替换为Jan Simon's functions之一,可以进一步改善上述情况。