You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python实现无重复配对且无共同角色的随机配对代码正确性验证咨询

Python实现无重复配对且无共同角色的随机配对代码正确性验证咨询

我现在需要实现一个公司内部的随机配对功能,核心要求有两个:

  • 生成的配对从未在历史记录中出现过(包括反向配对,比如A-B和B-A算同一个配对,不能重复生成)
  • 配对的两人不能有任何共同的角色/头衔(比如Marcus Liu和Elena Petrova都有"Stream 3"角色,就不能配对)

我已经写了一段代码来实现这个功能,逻辑是先加载CSV里的历史配对记录,随机打乱人员列表后尝试配对,跳过不符合条件的组合,最后把新生成的配对追加保存回CSV。但我不确定代码是否完全符合预期,想请大家帮忙验证逻辑,或者指出可能存在的漏洞。

我的实现代码

import random
import pandas as pd

# 人员姓名及对应角色数组
names_and_titles = [
    ("Samantha Reyes", "Innovation", "Product Owner"),
    ("Ethan McAllister", "Data Scientist"),
    ("Priya Deshmukh", "Data Architect", "SMT"),
    ("Marcus Liu", "Stream 3"),
    ("Elena Petrova", "SMT", "Stream 3"),
]

# 从CSV加载已生成的历史配对
def load_seen_pairs_from_csv(prev_pairs2):
    df = pd.read_csv(prev_pairs2)
    seen_pairs = set()
    for _, row in df.iterrows():
        pair = (row['name1'], row['name2'])
        reverse_pair = (row['name2'], row['name1'])
        seen_pairs.add(pair)
        seen_pairs.add(reverse_pair)
    return seen_pairs

# 将新配对保存到CSV
def save_pairs_to_csv(prev_pairs2, pairs):
    df = pd.DataFrame(pairs, columns=['name1', 'name2'])
    df.to_csv(prev_pairs2, index=False, mode='a', header=False)

# 历史配对CSV文件路径
csv_file_path = 'prev_pairs2.csv'

# 初始化已出现的配对集合
seen_pairs = load_seen_pairs_from_csv(csv_file_path)

# 额外需要排除的配对(当前为空)
excluded_pairs = []

def create_unique_pairs_with_debugging_and_fallback(names_and_titles, seen_pairs, excluded_pairs):
    excluded_set = set(excluded_pairs) | set((pair[1], pair[0]) for pair in excluded_pairs)  # 包含反向配对
    max_retries = 10000  # 增加重试次数提高配对成功率
    retries = 0
    
    while retries < max_retries:
        random.shuffle(names_and_titles)
        pairs = []
        used_names = set()  # 记录本次运行中已配对的人员
        skipped = []  # 记录跳过的人员用于调试
        
        for i in range(0, len(names_and_titles) - 1, 2):
            person1, person2 = names_and_titles[i], names_and_titles[i + 1]
            # 获取两人的角色集合(处理不同长度的元组)
            roles1 = set(person1[1:]) if len(person1) > 1 else set()
            roles2 = set(person2[1:]) if len(person2) > 1 else set()
            
            pair = (person1[0], person2[0])
            reverse_pair = (person2[0], person1[0])
            
            # 调试日志:输出跳过原因
            if pair in excluded_set or reverse_pair in excluded_set:
                print(f"因在排除列表中,跳过配对: {person1[0]} - {person2[0]}")
                continue
            if pair in seen_pairs or reverse_pair in seen_pairs:
                print(f"因已存在历史配对,跳过配对: {person1[0]} - {person2[0]}")
                continue
            if roles1 & roles2:  # 角色有交集则跳过
                print(f"因存在共同角色,跳过配对: {person1[0]} ({roles1}) - {person2[0]} ({roles2})")
                continue
            if person1[0] in used_names or person2[0] in used_names:
                print(f"因人员已被配对,跳过配对: {person1[0]} - {person2[0]}")
                continue
            
            pairs.append((person1, person2))
            used_names.update([person1[0], person2[0]])  # 标记人员为已使用
        
        # 收集未被配对的人员
        skipped = [person for person in names_and_titles if person[0] not in used_names]
        if not skipped:  # 所有人都成功配对
            pairs_set = set((pair[0][0], pair[1][0]) for pair in pairs)
            # 再次验证配对是否都不在历史记录中(双重保险)
            if not any((pair in seen_pairs or (pair[1], pair[0]) in seen_pairs) for pair in pairs_set):
                seen_pairs.update(pairs_set)
                return pairs
        
        retries += 1
    
    # 重试次数耗尽仍无法完成配对
    print("无法在给定限制条件下生成有效配对。")
    print(f"未被配对的人员: {[person[0] for person in skipped]}")
    raise ValueError("无法在给定限制条件下生成有效配对。")

# 生成符合要求的唯一配对
unique_pairs = create_unique_pairs_with_debugging_and_fallback(names_and_titles, seen_pairs, excluded_pairs)

# 输出配对结果(仅姓名)
for pair in unique_pairs:
    print(f"{pair[0][0]} - {pair[1][0]}")
print("-----")
# 输出配对总数
print(f"总配对数: {len(unique_pairs)}")

# 将新配对保存到CSV
save_pairs_to_csv(csv_file_path, [(pair[0][0], pair[1][0]) for pair in unique_pairs])

我的疑问与验证点

  1. 角色判断逻辑:我最初误写为roles1 = set(person1[2:]),后来修正为person1[1:](因为元组第一个元素是姓名,后续所有元素都是角色),这个修正是否正确?
  2. 奇数人数处理:当人员数量为奇数时,总会有1人无法配对,代码会一直重试直到找到全员可配对的组合吗?但如果历史配对积累到一定程度,可能确实无法生成全员配对,这种场景的报错处理是否合理?
  3. CSV追加逻辑:使用mode='a'追加写入新配对,结合生成时的历史配对检查,是否能绝对避免重复写入同一配对?
  4. 反向配对处理:代码中把A-B和B-A都加入历史配对集合,是否能完全防止反向配对被重复生成?
  5. 还有没有其他我没考虑到的逻辑漏洞?比如人员重复配对、角色交集判断错误等?

火山引擎 最新活动