如何在python中生成数组的排列?

Posted

技术标签:

【中文标题】如何在python中生成数组的排列?【英文标题】:how to generate permutations of array in python? 【发布时间】:2011-01-08 14:56:18 【问题描述】:

我有一个包含 27 个元素的数组,我不想生成数组的所有排列(27 个!) 我需要 5000 个随机选择的排列,任何提示都会很有用...

【问题讨论】:

值得一提的是,27! 是 10888869450418352160768000000。 【参考方案1】:

要生成一个排列,请使用random.shuffle 并存储结果的副本。在循环中重复此操作,每次检查是否有重复项(但可能不会有任何重复项)。一旦您的结果集中有 5000 个项目,请停止。

针对评论中的点,Python的random module是基于Mersenne Twister,有2**19937-1的句号,比27!大很多,所以应该适合你使用。

【讨论】:

+1,但请注意random.shuffle 有一个严重的弱点:随着 n 变大,大多数 RNG 的周期小于排列的总数。这意味着几乎不可能生成足够大 n 的所有可能排列,因此这不是真正的随机。 确实,约翰。 Python 的随机生成器的周期为 2**19937-1,所以它可能已经足够好了。另一个挑剔的是,对于真正的随机数,您需要一个真正的随机源(例如来自放射性衰变),Python 的 random 模块仅提供伪随机数。但通常人们说“随机”时,他们真正的意思是“伪随机”,我认为这就是这里的海报的意思。 +1 酷!这是一个很大的骰子,有 10888869450418352160768000000 个面,其中任何一个出现的概率是 1/10888869450418352160768000000。不能重复!! @PratikDeoghare 这是一个带有 6002 位数面数的大骰子,但它以特定的已知模式旋转,并且面的负载具有相同的数字。重复是的方式。 其中任意一个相等的概率为1/10888869450418352160768000000,但none相等的概率更大。例如,如果您采用27!+1 排列,即使其中一个与另一个相等的概率很小,没有重复的概率也是0。在这种情况下,因为27! >> 5000,至少有一个重复的概率是(1/27)*5000。仍然很小,但不一样了。【参考方案2】:
import random

perm_list = []

for i in range(5000):
    temp = range(27)
    random.shuffle(temp)
    perm_list.append(temp)

print(perm_list)

10888869450418352160768000000我喜欢大数字! :)

10888869450418352160768000001 是 PRIME!!

编辑:

#with duplicates check as suggested in the comment

perm_list = set()
while len(perm_list)<5000:
    temp = range(27)
    random.shuffle(temp)
    perm_list.add(tuple(temp)) # `tuple` because `list`s are not hashable. right Beni?

print perm_list

警告:如果 RNG 不好,这将永远不会停止!

【讨论】:

要像 Mark 建议的那样检查重复项,请使用 perms = set()perms.add(tuple(temp))while len(perms) &lt; 5000 而不是 for 循环。 @Beni 我一开始没有听从你的tuple(temp) 建议,但后来我明白我是个傻瓜!!谢谢大佬!【参考方案3】:

itertools.permutations。它是一个生成器,因此它不会创建整个排列列表。你可以随机跳过,直到你有 5000 个。

【讨论】:

这并不是真正的“随机”,因为itertools 按定义的顺序创建它们,并且排列的数量是有限的。更好的是执行以下操作:(1) 确定存在 多少 排列(将此数字称为 N),(2) 然后在 0..N-1 范围内生成 5,000 个不同的随机索引, (3) 从 itertools.permutations 生成器中选择与这些索引相对应的排列。 是的,我知道这不是最好的。我第一次阅读这个问题时,不知何故没有注意到“随机选择”的部分。我不会删除它,也许有人在搜索“如何在 python 中生成数组的排列?”会发现它很有用。 @Cat Plus Plus 那就是我:D【参考方案4】:
# apermindex should be a number between 0 and factorial(len(alist))
def perm_given_index(alist, apermindex):
    for i in range(len(alist)-1):
        apermindex, j = divmod(apermindex, len(alist)-i)
        alist[i], alist[i+j] = alist[i+j], alist[i]
    return alist

用法:perm_given_index(['a','b','c'], 3)

这使用 Lehmer 代码进行排列,因为 j 的值与之匹配。

【讨论】:

如果您需要存储大量排列以改用整数表示,这可能非常好,即用于压缩。受到启发写了gist.github.com/lukmdo/7049748 Lehmer 编码(和解码)应该被安置在核心 python 中的某个地方——至少,作为 itertools 的一部分。任何使用排列很常见的东西都需要一种与相关 Lehmer 索引相互转换的方法。【参考方案5】:

您可能需要 itertools.permutations() 函数。一定会喜欢那个 itertools 模块!

注意:2.6 中的新功能

【讨论】:

这太慢了 - 他说他有 27 个元素。【参考方案6】:

您可以尝试实现random_permutation itertools recipes。为方便起见,我使用了第三方库more_itertools,它为我们实现了这个秘诀:

import more_itertools as mit

iterable = range(27)
mit.random_permutation(iterable)
# (24, 3, 18, 21, 17, 22, 14, 15, 20, 8, 4, 7, 13, 6, 25, 5, 12, 1, 9, 19, 23, 11, 16, 0, 26, 2, 10)

每次调用函数都会创建一个随机排列。我们可以制作一个生成器,为n 调用产生这些结果。我们将实现这个生成器并通过一个简短的示例演示随机结果:

def random_permute_generator(iterable, n=10):
    """Yield a random permuation of an iterable n times."""
    for _ in range(n):
        yield mit.random_permutation(iterable)

list(random_permute_generator(range(10), n=20))
# [(2, 7, 9, 6, 5, 0, 1, 3, 4, 8),
#  (7, 3, 8, 1, 2, 6, 4, 5, 9, 0),
#  (2, 3, 1, 8, 7, 4, 9, 0, 6, 5),
#  (0, 5, 6, 8, 2, 3, 1, 9, 4, 7),
#  (0, 8, 1, 9, 4, 5, 7, 2, 3, 6),
#  (7, 2, 5, 8, 3, 4, 1, 0, 9, 6),
#  (9, 1, 4, 5, 8, 0, 6, 2, 7, 3),
#  (3, 6, 0, 2, 9, 7, 1, 4, 5, 8),
#  (8, 4, 0, 2, 7, 5, 6, 1, 9, 3),
#  (4, 9, 0, 5, 7, 1, 8, 3, 6, 2)
#  ...]

针对您的具体问题,将可迭代的调用次数和调用次数n 替换为适当的值,例如random_permute_generator(iterable, n=5000).

有关此工具的更多信息,另请参阅 more_itertools docs。


详情

对于那些感兴趣的人,这里是实际的食谱。

来自itertools recipes:

def random_permutation(iterable, r=None):
    "Random selection from itertools.permutations(iterable, r)"
    pool = tuple(iterable)
    r = len(pool) if r is None else r
    return tuple(random.sample(pool, r))

【讨论】:

以上是关于如何在python中生成数组的排列?的主要内容,如果未能解决你的问题,请参考以下文章

如何在RC4中生成键串

如何从所有排列中生成所有可能的组合?

如何在 R 中生成对象的排列或组合?

如何在 PHP 中生成字符串的所有排列?

如何在 m 列中生成 n 行的排列或组合?

如何在一个 1×41 向量中生成定位 20 个 -1 值的每个排列?