ある時点までは、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 およびn
< 100000 ですが、保証が必要な場合、または の値が小さい場合はlen(l)
、 a を使用し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
が大きな に対して信頼できなくなる理由を理解するlen(l)
には、次の点を考慮してください。random.shuffle
との間の乱数のみを選択する必要が0
ありlen(l) - 1
ます。ただし、内部状態に基づいてこれらの数値を選択し、有限の (および固定の) 数の状態しか取ることができません。同様に、渡すことができるシード値の数は有限です。これは、生成できる一意の数列のセットも有限であることを意味します。そのセットを呼び出しますs
。の場合、それらの順列に対応するシーケンスが にないためlen(l)! > len(s)
、一部の順列は生成できませんs
。
これが問題になる正確な長さはどれくらいですか? わからない。しかし、価値があるのは、によって実装されているメルセンヌツイスターの周期random
は2**19937-1です。シャッフルのドキュメントでは、一般的な方法で私の主張を繰り返しています。ウィキペディアのこの問題に関するコメントも参照してください。