【问题标题】:Generating permutations of a set with controlled output?生成具有受控输出的集合的排列?
【发布时间】:2015-05-01 16:23:18
【问题描述】:

有没有一种简单的方法可以得到一个集合的前 x 个排列?

例如一个有 5 个字符 {a,b,c,d,e} 的集合将有

5*5*5*5*5= 3125 个排列输出

(允许重复,例如 {a,a,a,a,a})

但我希望只有前 100 个值,例如

【问题讨论】:

  • 您认为“第一个”x 排列是什么?例如100 个随机可能的排列,或某种顺序的排列?另外,考虑到你的数学,你的意思是 {a,a,a,a,a} 是一个选项吗?
  • 是的,{a,a,a,a,a} 是一个选项,是的,随机也可以
  • 您应该更新您的问题以表明这一点,因为 MATLAB 中的大多数 permute/perms 等置换函数都假定真正的置换(无重复)。
  • 那些不是排列,而是组合。
  • permutations 中,通常不允许您两次使用同一个项目。我猜您要查找的术语是 Cartesian product 甚至可能是 Cartesian power

标签: matlab permutation


【解决方案1】:

一种按字典顺序同时生成所有“排列”的方法,而不必将它们全部存储在内存中:

function permute_chars(alphabet, nword, nmax)

if nargin < 3  % default to displaying all, this can be a huge number!
    nmax = nchar^nword;
end

nchar = length(alphabet);
ind = zeros(1, nword);
i = 0;

while i < nmax
    % just printing the permutaions, edit according to your needs
    disp(cell2mat(alphabet(ind + 1))); 

    % calculate next indices, classic elementary school addition with carry
    ind(end) = ind(end) + 1;
    for j = nword:-1:2
        if ind(j) == nchar 
            ind(j) = 0;  % wrap around
            ind(j-1) = ind(j-1) + 1;  % carry
        end
    end     
    i = i + 1;
end

当然,我忘记了一些晦涩难懂的函数,它可以用更少的行来实现它,但是这样写很清楚它是如何工作的。快速测试:

>> alphabet = {'a', 'b', 'c', 'd', 'e'};
>> permute_chars(alphabet, 1)
a
b
c
d
e
>> permute_chars(alphabet, 2)
aa
ab
ac
ad
ae
ba
[... snip ...]
ed
ee

只打印有限数量的排列:

>> permute_chars(alphabet, 5, 8)
aaaaa
aaaab
aaaac
aaaad
aaaae
aaaba
aaabb
aaabc

【讨论】:

    【解决方案2】:

    您可以使用P = perms(S) 来获取集合S 的所有排列,然后如果您想要100,您可以使用P(1:100,:)

    对于随机,您可以使用P(randperm(size(P,1),100),:)

    如果您知道需要更具体地了解排列,那么您可以使用 permuteorder 参数 - http://uk.mathworks.com/help/matlab/ref/permute.html

    【讨论】:

    • 嗨 crwissy,事情是我们将生成一个巨大的列表,如果我们不控制它,我们将耗尽内存(例如 22^10)
    【解决方案3】:

    要从数字1:n 中选择 100 个随机唯一样本,允许重复(带替换抽样),您可以使用randi 或类似方法创建一个比100 x n 多一点的随机样本列表,unique他们删除重复项,然后取前 100 个。

    例如,使用randi:

    % from numbers 1:n, create 200 by n random matrix
    sample_list = randi(n,[200, n]);
    % remove duplicates
    sample_list = unique(sample_list,'rows'); 
    % you should probably error check here
    % presuming there's >100 options left, take 100 of them
    sample_list = sample_list(1:100,:);
    

    sample_list 将是一个数字矩阵,但如果需要,您可以轻松地将其用作其他事物的索引:

    my_set = {'a','b','c','d','e'}; % 1 x 5 cell
    my_permutes = my_set(sample_list); % 100 x 5 cell
    

    这避免了必须计算每个可能的选项,这对于较大的n 会成为问题。

    【讨论】:

      【解决方案4】:

      为了在获得的排列范围内获得更多的灵活性,您可以使用一个函数,该函数在给定排列的情况下产生系列中的下一个排列。在这个实现中,我选择让排列回绕到第一个,即使输入排列超出范围。

      function newperm = nextPerm(oldperm, base)
         if any(oldperm >= base)
            newperm = zeros(1,numel(oldperm));
            return
         end
         idx = numel(oldperm);
         newperm = oldperm;
         while idx > 0
            newperm(idx) = newperm(idx) + 1;
            if newperm(idx) < base
               return;
            end
            newperm(idx) = 0;
            idx = idx - 1;
         end
      end
      

      排列元素是从 0 开始的(所以最大元素是 base-1)。

      p = [4 4 4 4 4]
      nextPerm(p, 5)
      ans =
      
         0   0   0   0   0
      
      p = [0 0 0 0 0]
      nextPerm(p, 5)
      ans =
      
         0   0   0   0   1
      
      p = [3 4 1 0 2]
      nextPerm(p, 5)
      ans =
      
         3   4   1   0   3
      
      p = [3 4 5 0 2] %// invalid value '5'
      nextPerm(p, 5)
      ans =
      
         0   0   0   0   0
      

      要获得一个范围,只需通过循环输入它:

      myPerms = zeros(5);
      myPerms(1,:) = [3 1 2 0 4];
      for k = 2:5
         myPerms(k,:) = nextPerm(myPerms(k-1,:), size(myPerms,1));
      end
      
      myPerms =
      
         3   1   2   0   4
         3   1   2   1   0
         3   1   2   1   1
         3   1   2   1   2
         3   1   2   1   3
      

      要将排列映射到您的字母表,只需将 1 添加到向量并将其用作索引:

      alphabet = ['a', 'b', 'c', 'd', 'e'];
      word = alphabet(myPerms(1,:)+1)
      
      word = dbcae
      

      【讨论】:

        猜你喜欢
        • 2012-06-27
        • 2016-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-11
        • 1970-01-01
        • 2013-01-28
        相关资源
        最近更新 更多