You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python圣诞抽名脚本执行耗时不稳定问题排查与优化求助

圣诞节送礼配对脚本卡顿问题排查与解决

问题描述

我正在学习Python,写了个“从帽子里抽名字”的脚本用来做圣诞节送礼配对,脚本能正常运行,但执行时间极不稳定——有时候秒出结果,有时候卡5分钟都完不成。想搞清楚原因,找到能稳定运行的解决办法。

我的实现步骤如下:

  1. 创建两个相同名单并打乱:
fam1 = ["name1", "name2", "name3", "name4", "name5", "name6", "name7"]
fam2 = ["name1", "name2", "name3", "name4", "name5", "name6", "name7"]
fam1_shuffled = random.sample(fam1, len(fam1))
fam2_shuffled = random.sample(fam2, len(fam2))
  1. 定义禁止配对的字典:
not_allowed_pairs = {
    "name1": "name4",
    "name4": "name1", 
    "name3": "name6", 
    "name6": "name3"
}
  1. 核心配对函数:
def pick_names(list1, list2): 
    pairs = {}
    gifters = list1
    used_names = []
    while len(pairs) < len(gifters): 
        for i in range(len(list1)): 
            if ((gifters[i] != list2[i]) & (list2[i] not in used_names)): 
                k = gifters[i]
                v = list2[i]
                if (k, v) not in non_allowed_pairs.items(): 
                    pairs[k] = v
                    used_names.append(v)
    return pairs
  1. 结果输出函数:
def print_picks(pair_dict):
    for k, v in pair_dict.items():
        print(f"{k} picked: {v}")      

卡顿原因

你的核心逻辑存在无限循环风险,这是导致卡顿的根本原因:

  • 循环逻辑缺陷:外层while循环依赖pairs的长度增长,但内层for循环每次遍历只能匹配部分符合条件的项。如果剩下的未配对人员找不到合法的配对(比如最后一个人剩下的唯一可选对象是自己或禁止配对的人),pairs的长度就不会再增加,while循环会无限执行下去。
  • 低效的条件判断:list2[i] not in used_names是线性查找,虽然7个元素影响不大,但也是额外性能开销;另外你用了位运算符&代替逻辑运算符and,虽然结果没问题,但属于用法错误。
  • 配对逻辑不严谨:简单从两个打乱的列表按索引匹配,没有处理“配对耗尽合法选项”的死局情况,随机打乱后的组合可能永远无法完成全部配对。

解决办法

正确思路是生成符合规则的合法排列——每个人抽到别人,且避开禁止配对,而非靠随机打乱硬凑。推荐两种可靠实现:

方法1:基于随机排列的重试机制

每次生成随机排列,检查是否符合规则,不符合就重新生成,直到找到合法结果:

import random

fam = ["name1", "name2", "name3", "name4", "name5", "name6", "name7"]
not_allowed_pairs = {
    "name1": "name4",
    "name4": "name1", 
    "name3": "name6", 
    "name6": "name3"
}

def generate_valid_pairs():
    while True:
        # 生成随机排列,模拟抽名字的过程
        recipients = random.sample(fam, len(fam))
        valid = True
        # 检查两个核心规则:没人抽到自己,无禁止配对
        for giver, receiver in zip(fam, recipients):
            if giver == receiver or not_allowed_pairs.get(giver) == receiver:
                valid = False
                break
        if valid:
            return dict(zip(fam, recipients))

def print_picks(pair_dict):
    for k, v in pair_dict.items():
        print(f"{k} picked: {v}")  

# 生成并输出结果
pairs = generate_valid_pairs()
print_picks(pairs)

对于7个人的规模,几乎不会多次重试,执行速度极快。

方法2:改进原逻辑,避免死循环

如果想保留列表配对思路,每次循环重新打乱列表,直到能生成完整合法配对:

import random

fam = ["name1", "name2", "name3", "name4", "name5", "name6", "name7"]
not_allowed_pairs = {
    "name1": "name4",
    "name4": "name1", 
    "name3": "name6", 
    "name6": "name3"
}

def pick_names(gifters):
    while True:
        recipients = random.sample(gifters, len(gifters))
        pairs = {}
        used = set()
        valid = True
        for giver, receiver in zip(gifters, recipients):
            if giver == receiver or receiver in used or not_allowed_pairs.get(giver) == receiver:
                valid = False
                break
            pairs[giver] = receiver
            used.add(receiver)
        # 确认所有人都完成配对
        if len(pairs) == len(gifters):
            return pairs

def print_picks(pair_dict):
    for k, v in pair_dict.items():
        print(f"{k} picked: {v}")  

fam_shuffled = random.sample(fam, len(fam))
pairs = pick_names(fam_shuffled)
print_picks(pairs)

用set存储已使用的名字,查找速度比列表快;同时每次循环直接检查能否生成完整合法配对,不行就重新打乱,彻底避免了原逻辑的无限循环问题。


内容的提问来源于stack exchange,提问作者Josh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 21:25:39