问题描述
虽然我知道循环算法可以很容易地用于一次性流程,但我需要创建一个循环算法来引用之前运行的结果,并确保长时间内没有重复的匹配.
我正在尝试创建一个脚本,该脚本从 Google 表格中获取姓名列表,一次随机匹配两个姓名,为这两个人安排会议并将配对写回表格以保留历史记录,以便确保下次运行脚本时不会发生配对。
这实际上是一个“循环”概念,每个人只与其他人随机匹配一次。该脚本每周运行一次以创建每周一次的会议。
以下是流程概览:
- 从工作表中拉取姓名列表
- 随机选择两个名字来创建一个“配对”
- 通过引用具有历史配对的工作表来检查此配对之前未发生过
- 如果是新配对,请创建一个事件并将配对写回工作表
- 如果不是新配对,请取消配对并重试
- 继续循环直到所有名字都配对,或者直到剩下一个/没有新的配对可能
我已经有代码可以工作了,但它非常杂乱无章。我目前的做法基本上是
names = [<names taken from Sheet via API>]
for name in names:
person1 = random.choice(names)
names.remove(person1)
person2 = random.choice(names)
names.remove(person2)
match = person1 + "," + person2
<logic for calling Sheets API with current match to make sure it hasn't prevIoUsly happened>
我有更多的代码来处理其他元素,比如调用不同的 API 来获取/发布数据,但我确信有更好的方法来做到这一点。
目前脚本有效,但是一旦“姓名”列表下降到最后几个人,它通常会失败,因为所有剩余的人之前都已相互匹配,或者有一个奇怪的人,所以抛出一个错误,没有正确处理。
解决方法
我通常可以想到一个更简单的方法:
- 生成所有可能配对的序列
- 从此序列中选择不包含重复项的条目
- 一次性转储所有每周会议列表
所以基本上,我建议您预先列出所有列表。这将使代码更简单,结果也不会减少随机性。
from itertools import combinations
from random import shuffle
names = ['A','B','C','D']
options = list(combinations(names,2))
shuffle(options)
def make_week(options):
week = []
remainder = []
seen = set()
for p1,p2 in options:
if p1 not in seen and p2 not in seen:
week.append((p1,p2))
seen.add(p1)
seen.add(p2)
else:
remainder.append((p1,p2))
return week,remainder
remainder = options
while len(remainder) >= len(names) // 2:
week,remainder = make_week(remainder)
# Dump the list for that week
注意我们只需要打乱一次:remainder
保留了原始列表的顺序。此版本假设您的姓名列表不会每周更改。如果是这样,您可以使用大部分相同的概念来生成下周的日程安排。
例如,假设您将上周的会议加载为包含名称的二元组列表:
last_week = [('B','D'),('A','C')]
您可以从一组有效选项中删除 last_week
的元素。为避免必须检查两种组合,请确保先对 names
进行排序:
names.sort()
options = set(combinations(names,2))
for item in last_week:
options.remove((min(item),max(item)))
options = list(options)
shuffle(options)