从列表中形成随机对(有点......)

ren*_*nat 5 python random list

跳到上次编辑

我有一个Person对象列表,我需要随机配对一个randomize_pairs函数,每个Person对象都有一个target与之配对的属性.

我的约束是没有人可以自己配对(duh),他们不应该与同一个人配对两次.

如果约束条件得到满足,我会通过制作一个临时列表和弹出人员来解决这个问题,但我确信有更清洁/更好/更多的pythonic方法.谁知道?


编辑

我在这个问题中经常使用"对"这个词,但那是错误的.这是为了一个游戏,每个人被指定为另一个人作为目标,所以这些是你的目标的目标不一定是你的单向关系.

目标只会在每轮开始时改变,所以它一下子全部改变.


编辑2

这就是我现在已经解决的问题,虽然它可以改进,所以我将问题保持开放.

def randomize_targets(players):
    # get player count
    count = len(players)
    # copy the list of players
    available_targets = list(players)
    # shuffle the player order so if the last one has to have the same
    # target twice it's not always the same player
    players = list(players)
    random.shuffle(players)
    # loop over each player
    for player in players:
        # get the list of possible targets
        potential_targets = [target for target in available_targets \
                             if target != player \
                             and target != player.target]
        # try to pick one at random
        try:
            target = random.choice(potential_targets)
        # if we have to, use the same target as last time
        except IndexError:
            pass
        # remove the target from the available targets list
        available_targets.remove(target)
        # assign target
        player.target = target
Run Code Online (Sandbox Code Playgroud)

编辑3

我决定使用这种方法,即使我不喜欢潜在的长时间循环,直到它找到一个至少起作用的组合,它总是产生有效的结果

def randomize_targets2 (players):
    targets = list(players)
    # run this until it generates a valid result
    valid = False
    while not valid:
        # randomize the targets
        random.shuffle(targets)
        # validate them
        round_valid = True
        for player, target in zip(players, targets):
            round_valid = round_valid and player != target and player.target != target
        valid = round_valid

    # apply the validated targets
    for player, target in zip(players, targets):
        player.target = target
Run Code Online (Sandbox Code Playgroud)

don*_*ton 6

我假设因为你想随机选择人,你选择的列表提供快速随机访问.一个简单的解决方案就是对整个列表进行洗牌,然后从列表的前面成对配对.

费雪耶茨洗牌是随机洗牌列表中的快捷,简便的方法.

然后你可以直接将它们配对:

for x from 0 to persons.size(), x += 2
    pair(persons.get(i), persons.get(i + 1));
Run Code Online (Sandbox Code Playgroud)

由于元素是独一无二的,您不必担心人们会两次配对或与自己配对.

还要小心确保您的清单首先有偶数人!如果总数是奇数,你将不得不以某种方式处理列表末尾的额外人员.

  • 这不是Python.2.为了改组使用[Fischer-Yates](https://secure.wikimedia.org/wikipedia/en/wiki/Fisher-Yates_shuffle#The_modern_algorithm),我认为改组算法是有偏见的. (2认同)
  • 为什么不使用`random`模块中的`shuffle`? (2认同)