跳至上一次修改
我有一个Person
个对象的列表,我需要将它们与randomize_pairs
函数随机配对,每个Person
对象都有一个属性target
配对。
我的限制是没有人可以与自己配对(duh),他们不应该与同一个人配对两次。
我通过制作一个临时列表来解决这个问题,如果满足约束条件就会让人们离开,但我确信有更清洁/更好/更pythonic的方法。有人知道吗?
我在这个问题中经常使用“对”这个词,但那是错误的词。这是针对一个游戏,每个人被指定为另一个人作为目标,所以这些是单向关系,你的目标不一定是你的目标。
目标只会在每轮开始时更改,所以一次性完成。
以下是我现在已经解决的问题虽然可以改进,但我将问题保持开放。
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
我决定采用这种方法,即使我不喜欢潜在的长时间循环,直到找到一个至少起作用的组合,它总能产生有效的结果
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
答案 0 :(得分:6)
我认为,由于您想随机选择人,因此您选择的列表可以提供快速随机访问。一个简单的解决方案就是对整个列表进行洗牌,然后从列表的前面成对配对。
Fisher-Yates shuffle是一种随机播放列表的快捷方式。
然后你可以直接将它们配对:
for x from 0 to persons.size(), x += 2
pair(persons.get(i), persons.get(i + 1));
由于元素是独一无二的,因此您不必担心人们会两次配对或与自己配对。
另外要小心确保您的列表首先包含偶数人数!如果总数是奇数,你将不得不以某种方式处理列表末尾的额外人员。
答案 1 :(得分:1)
您可以使用列表获取所有可用人员
您还可以将每个人的dict映射到他们已经配对的所有人的一组(并且还包括他们自己组中的每个人)。
然后对于每个人,你可以用他们已经配对的一组人来减去所有人的集合,并对该集合中的任何项目进行采样(使用random.sample)(设置减法可能非常有效)。
您还需要确保如果您将人A与人B配对,那么当B轮到来时,您会注意到现有的配对并且只是跳过该迭代。
当然,不要忘记用新的配对更新你的字典,这样你就不会再次制作相同的配对。
这种方法对我来说似乎很优雅,因为你可以很容易地添加任意忽略规则(即A人永远不想与B人配对),只需在相关集中添加它们即可。