参考 Python 中以前的配对时的循环配对

问题描述

虽然我知道循环算法可以很容易地用于一次性流程,但我需要创建一个循环算法来引用之前运行的结果,并确保长时间内没有重复的匹配.

我正在尝试创建一个脚本,该脚本从 Google 表格中获取姓名列表,一次随机匹配两个姓名,为这两个人安排会议并将配对写回表格以保留历史记录,以便确保下次运行脚本时不会发生配对。

这实际上是一个“循环”概念,每个人只与其他人随机匹配一次。该脚本每周运行一次以创建每周一次的会议。

以下是流程概览:

  1. 从工作表中拉取姓名列表
  2. 随机选择两个名字来创建一个“配对”
  3. 通过引用具有历史配对的工作表来检查此配对之前未发生过
  4. 如果是新配对,请创建一个事件并将配对写回工作表
  5. 如果不是新配对,请取消配对并重试
  6. 继续循环直到所有名字都配对,或者直到剩下一个/没有新的配对可能

我已经有代码可以工作了,但它非常杂乱无章。我目前的做法基本上是

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)