蟒蛇洗牌,使得位置绝不重复(python shuffle such that position wi

2019-07-22 01:15发布

我希望做一个列表的随机洗牌,但有一个条件:一个元素可以永远在洗牌后同原来的位置。

有没有一条线的方式在Python的名单做这样?

例:

list_ex = [1,2,3]

以下每个洗牌名单应具备的洗牌后,被采样的相同的概率:

list_ex_shuffled = [2,3,1]
list_ex_shuffled = [3,1,2]

但排列[1,2,3],[1,3,2],[2,1,3]和[3,2,1]的不允许的,因为它们都重复元件位置中的一个。

注:在list_ex每个元素都是一个唯一的ID。 同一元素的无重复是允许的。

有任何想法吗? 谢谢!

Answer 1:

随机在一个循环,并保持拒绝的结果,直到你的条件:

import random

def shuffle_list(some_list):
    randomized_list = some_list[:]
    while True:
        random.shuffle(randomized_list)
        for a, b in zip(some_list, randomized_list):
            if a == b:
                break
        else:
            return randomized_list


Answer 2:

您可以生成所有可能的有效shufflings:

>>> list_ex = [1,2,3]
>>> import itertools

>>> list(itertools.ifilter(lambda p: not any(i1==i2 for i1,i2 in zip(list_ex, p)),
...                        itertools.permutations(list_ex, len(list_ex))))
[(2, 3, 1), (3, 1, 2)]

对于一些其他的序列:

>>> list_ex = [7,8,9,0]
>>> list(itertools.ifilter(lambda p: not any(i1==i2 for i1,i2 in zip(list_ex, p)),
...                        itertools.permutations(list_ex, len(list_ex))))
[(8, 7, 0, 9), (8, 9, 0, 7), (8, 0, 7, 9), (9, 7, 0, 8), (9, 0, 7, 8), (9, 0, 8, 7), (0, 7, 8, 9), (0, 9, 7, 8), (0, 9, 8, 7)]

你也可以将这个多一点有效的通过短路迭代器,如果你只是想要一个结果:

>>> list_ex = [1,2,3]
>>> i = itertools.ifilter(lambda p: not any(i1==i2 for i1,i2 in zip(list_ex, p)),
...                       itertools.permutations(list_ex, len(list_ex)))
>>> next(i)
(2, 3, 1)

但是,它不会是一个随机的选择。 你不得不产生所有这些,选择一个它是一个实际的随机结果:

>>> list_ex = [1,2,3]
>>> i = itertools.ifilter(lambda p: not any(i1==i2 for i1,i2 in zip(list_ex, p)),
...                       itertools.permutations(list_ex, len(list_ex)))
>>> import random
>>> random.choice(list(i))
(2, 3, 1)


Answer 3:

我想描述这种慢腾腾的“排列没有固定点”。 他们也被称为紊乱 。

一个随机排列是紊乱的概率大约是1 / e的(有趣的证明)。 这是真实的但是长的名单。 因此,一个明显的算法,得到无规紊乱是正常洗牌,并保持洗牌,直到你有一个精神错乱。 必要洗牌的预期数量约为3,这是罕见的,你必须洗牌十倍以上。

(1-1/e)**11 < 1%

假设有N多人在一个聚会上,每个人带了一把伞。 在晚会结束时,每个人从篮下取伞随意。 是什么,没有人拥有自己的伞的概率是多少?



Answer 4:

下面是这个别人得。 您可以根据您的需要选择一个解决方案或其他。 这不是一个衬垫,但洗牌元素,而不是元素本身的指标。 因此,原来的名单可能有重复的值或者无法比拟的类型的值,也可以是比较昂贵的。

#! /usr/bin/env python
import random

def shuffled_values(data):
    list_length = len(data)
    candidate = range(list_length)
    while True:
        random.shuffle(candidate)
        if not any(i==j for i,j in zip(candidate, range(list_length))):
            yield [data[i] for i in candidate]

list_ex = [1, 2, 3]
list_gen = shuffled_values(list_ex)
for i in range(0, 10):
    print list_gen.next()

这给:

[2, 3, 1]
[3, 1, 2]
[3, 1, 2]
[2, 3, 1]
[3, 1, 2]
[3, 1, 2]
[2, 3, 1]
[2, 3, 1]
[3, 1, 2]
[2, 3, 1]

如果list_ex[2, 2, 2]该方法将继续产生[2, 2, 2]一遍又一遍。 其他的解决方案会给你空列表。 我不知道你在这种情况下,想要的东西。



Answer 5:

这里的另一种算法。 取卡随意。 如果你的第i个卡是卡我,把它放回去,然后再试一次。 唯一的问题是,如果当你到最后一张牌是你不想要的。 与其他的一次交换它。

我认为这是公平的(uniformally随机)。

import random

def permutation_without_fixed_points(n):
    if n == 1:
        raise ArgumentError, "n must be greater than 1"

    result = []
    remaining = range(n)

    i = 0
    while remaining:
        if remaining == [n-1]:
            break

        x = i
        while x == i:
            j = random.randrange(len(remaining))
            x = remaining[j]

        remaining.pop(j)
        result.append(x)

        i += 1

    if remaining == [n-1]:
        j = random.randrange(n-1)
        result.append(result[j])
        result[j] = n

    return result


文章来源: python shuffle such that position will never repeat