jip*_*oe4 5 python random permutation discrete-mathematics python-3.x
假设我有一个任意长度的Python列表k.现在,假设我想要随机抽样n,(其中n <= k!)该列表的不同排列.我很想尝试:
import random
import itertools
k = 6
n = 10
mylist = list(range(0, k))
j = random.sample(list(itertools.permutations(mylist)), n)
for i in j:
print(i)
Run Code Online (Sandbox Code Playgroud)
但是,当代码太大时,这段代码自然会变得非常缓慢k.鉴于我可能正在寻找n的排列数量与排列总数相比将相对较小,因此计算所有排列是不必要的.但重要的是,最终列表中的所有排列都不是重复的.
你会如何更有效地实现这一目标?记住,mylist可能是任何事情的清单,我只是list(range(0, k))为了简单而使用.
下面是我所做的 na\xc3\xafve 实现(@Tomothy32 很好地实现了,使用生成器的纯 PSL):
\n\nimport numpy as np\n\nmylist = np.array(mylist)\nperms = set()\nfor i in range(n): # (1) Draw N samples from permutations Universe U (#U = k!)\n while True: # (2) Endless loop\n perm = np.random.permutation(k) # (3) Generate a random permutation form U\n key = tuple(perm)\n if key not in perms: # (4) Check if permutation already has been drawn (hash table)\n perms.update(key) # (5) Insert into set\n break # (6) Break the endless loop\n print(i, mylist[perm])\nRun Code Online (Sandbox Code Playgroud)\n\n它依赖于numpy.random.permutation随机排列序列。
关键思想是:
\n\ntuple它int必须散列)以防止重复;这个 na\xc3\xafve 版本不会直接受到函数的阶乘复杂性O(k!)的影响,该函数在采样之前itertools.permutations会生成所有排列。k!
算法设计和复杂性有一些有趣的地方......
\n\n如果我们想确保循环能够结束,我们必须强制执行N <= k!,但这并不能保证。此外,评估复杂性需要知道在找到新的随机元组并破坏它之前,无限循环实际上会循环多少次。
我们来封装一下@Tomothy32写的函数:
\n\nimport math\ndef get_perms(seq, N=10):\n rand_perms = perm_generator(mylist)\n return [next(rand_perms) for _ in range(N)]\nRun Code Online (Sandbox Code Playgroud)\n\n例如,此调用适用于非常小的情况k<7:
get_perms(list(range(k)), math.factorial(k))\nRun Code Online (Sandbox Code Playgroud)\n\nO(k!)但是在复杂性(时间和内存)增长之前会失败k,因为它归结为在k!-1找到所有其他键后随机找到唯一的丢失键。
另一方面,当 时,该方法似乎可以在合理的时间内生成合理数量的排列元组N<<<k!。例如,可以在不到一秒的时间内绘制多个N=5000长度的元组。k10 < k < 1000
当k和N保持较小且N<<<k!时,算法似乎具有复杂性:
k;N.这在某种程度上是有价值的。
\n