到一定程度,没有必要使用get_nth_permutation
来获得排列。只是洗牌!
>>> import random
>>> l = range(21)
>>> def random_permutations(l, n):
... while n:
... random.shuffle(l)
... yield list(l)
... n -= 1
...
>>> list(random_permutations(l, 5))
[[11, 19, 6, 10, 0, 3, 12, 7, 8, 16, 15, 5, 14, 9, 20, 2, 1, 13, 17, 18, 4],
[14, 8, 12, 3, 5, 20, 19, 13, 6, 18, 9, 16, 2, 10, 4, 1, 17, 15, 0, 7, 11],
[7, 20, 3, 8, 18, 17, 4, 11, 15, 6, 16, 1, 14, 0, 13, 5, 10, 9, 2, 19, 12],
[10, 14, 5, 17, 8, 15, 13, 0, 3, 16, 20, 18, 19, 11, 2, 9, 6, 12, 7, 4, 1],
[1, 13, 15, 18, 16, 6, 19, 8, 11, 12, 10, 20, 3, 4, 17, 0, 9, 5, 2, 7, 14]]
出现在此列表中len(l)
大于 15 和< 100000的重复项的可能性压倒性地大n
,但是如果您需要保证,或者对于较低的评论,如果接近,这将停止)。就像是:len(l)
set
n
len(l)!
def random_permutations(l, n):
pset = set()
while len(pset) < n:
random.shuffle(l)
pset.add(tuple(l))
return pset
然而,随着len(l)
变得越来越长,random.shuffle
变得越来越不可靠,因为列表的可能排列的数量增加超出了随机数生成器的周期!因此,并非所有的排列都l
可以以这种方式生成。此时,您不仅需要映射get_nth_permutation
一系列随机数,还需要一个能够生成 和 之间的每个随机数的随机数生成0
器len(l)
!分布比较均匀。这可能需要您找到更强大的随机性来源。
然而,一旦你有了这个,解决方案就像Mark Ransom的回答一样简单。
要了解为什么random.shuffle
large 变得不可靠len(l)
,请考虑以下内容。random.shuffle
只需要在0
和之间选择随机数len(l) - 1
。但它会根据其内部状态选择这些数字,并且它只能采用有限(和固定)数量的状态。同样,您可以传递给它的可能种子值的数量是有限的。这意味着它可以生成的唯一数字序列集也是有限的;调用那个集合s
。对于len(l)! > len(s)
,永远无法生成某些排列,因为与这些排列相对应的序列不在s
.
What are the exact lengths at which this becomes a problem? I'm not sure. But for what it's worth, the period of the mersenne twister, as implemented by random
, is 2**19937-1. The shuffle docs reiterate my point in a general way; see also what Wikipedia has to say on the matter here.