python - 生成列表的随机排列

标签 python random permutation

我怎样才能随机打乱列表,使所有元素都不会留在原来的位置?

换句话说,给定一个包含不同元素的列表 A,我想生成它的排列 B 以便

  • 这个排列是随机的
  • 并且对于每个 na[n] != b[n]

例如

a = [1,2,3,4]
b = [4,1,2,3] # good
b = [4,2,1,3] # good

a = [1,2,3,4]
x = [2,4,3,1] # bad

我不知道这种排列的正确术语(是“总”吗?)因此很难用谷歌搜索。正确的术语似乎是“紊乱”。

最佳答案

经过一些研究,我能够实现“提前拒绝”算法,例如在 this paper .它是这样的:

import random

def random_derangement(n):
    while True:
        v = [i for i in range(n)]
        for j in range(n - 1, -1, -1):
            p = random.randint(0, j)
            if v[p] == j:
                break
            else:
                v[j], v[p] = v[p], v[j]
        else:
            if v[0] != 0:
                return tuple(v)

想法是:我们不断打乱数组,一旦我们发现我们正在处理的排列无效 (v[i]==i),我们就会中断并从头开始.

快速测试表明该算法均匀地生成所有紊乱:

N = 4

# enumerate all derangements for testing
import itertools
counter = {}
for p in itertools.permutations(range(N)):
    if all(p[i] != i for i in p):
        counter[p] = 0

# make M probes for each derangement
M = 5000
for _ in range(M*len(counter)):
    # generate a random derangement
    p = random_derangement(N)
    # is it really?
    assert p in counter
    # ok, record it
    counter[p] += 1

# the distribution looks uniform
for p, c in sorted(counter.items()):
    print p, c

结果:

(1, 0, 3, 2) 4934
(1, 2, 3, 0) 4952
(1, 3, 0, 2) 4980
(2, 0, 3, 1) 5054
(2, 3, 0, 1) 5032
(2, 3, 1, 0) 5053
(3, 0, 1, 2) 4951
(3, 2, 0, 1) 5048
(3, 2, 1, 0) 4996

为了简单起见,我选择了这个算法,this presentation简要概述了其他想法。

关于python - 生成列表的随机排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25200220/

相关文章:

windows - 随机文件生成器(再次!)

java - 有限制的排列

python - 有人可以解释这个 python 排列代码吗?

java - 在Java中根据种子创建一个随机整数数组

python - 随机 Python 模块和创造机会

python - 限制 Django-Filter 中字段的查询集

python - 用 os.path.join() 构造绝对路径

java - 2 个值之间的随机整数

c# - Fisher-Yates 在单个字符串上洗牌与使用等长排列?

python - 从 DataFrame 中的行中减去重复计数值