非常游戏网
如何修复Python中条件循环内列表随机化失效的问题

如何修复Python中条件循环内列表随机化失效的问题

2026-05-24日常编程66866

本文揭示了在while循环中反复调用随机化函数却始终无法满足约束条件的根本原因:原始timetable被重复追加列而非重置,导致约束检查始终作用于旧数据,新生成的列被忽略。

本文揭示了在while循环中反复调用随机化函数却始终无法满足约束条件的根本原因:原始timetable被重复追加列而非重置,导致约束检查始终作用于旧数据,新生成的列被忽略。

在优化类问题(如医院手术排程)中,使用随机初始化+约束验证的“生成-测试”策略非常常见。但若实现不当,极易陷入无限循环——表面看代码逻辑正确(while not valid: generate()),实则因对象状态未正确重置而失效。

问题核心在于 RandomiseTimetable() 函数的设计缺陷:

def RandomiseTimetable(timetable, surgeryData):  # ❌ 错误:传入并修改原列表
   for x in range(3):
       column = []
       for y in range(9):
           randomIndex = random.randint(0, len(surgeryData) - 1)
           randomRow = surgeryData.iloc[randomIndex]
           column.append({
               "surgery": randomRow["surgery"],
               "name": randomRow["name"],
               "requires_anaesthetist": randomRow["requires_anaesthetist"],
           })        
       timetable.append(column)   # ← 关键错误:向原timetable追加第4、5、6...列!
   return timetable

而约束检查函数 AnaesthetistsWithinLimit() 始终只读取前3列(索引 0, 1, 2):

comparisonArray = [timetable[0][j], timetable[1][j], timetable[2][j]]  # ← 永远只看前三列

因此,每次循环中:

Python 3.14.3

微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。

  • 第1次:timetable = [[T1], [T2], [T3]] → 检查有效,但若不满足则进入循环;
  • 第2次:timetable = [[T1], [T2], [T3], [T4], [T5], [T6]] → timetable[0], [1], [2] 仍是原始三列,新生成的列被完全忽略
  • 后续所有迭代均重复检查同一组旧数据 → 永远无法通过,无限打印“Constraint breached”。

✅ 正确做法是:让 RandomiseTimetable() 返回一个全新、干净的 timetable,而非修改原对象

import random

def RandomiseTimetable(surgeryData):
    """生成全新的3×9手术排程表,返回独立列表"""
    timetable = []
    for theatre_idx in range(3):  # 3个手术室
        column = []
        for slot_idx in range(9):  # 9个时段
            random_index = random.randint(0, len(surgeryData) - 1)
            row = surgeryData.iloc[random_index]
            column.append({
                "surgery": row["surgery"],
                "name": row["name"],
                "requires_anaesthetist": row["requires_anaesthetist"],
            })
        timetable.append(column)
    return timetable  # ✅ 返回新列表,不依赖外部状态

def AnaesthetistsWithinLimit(timetable, anaesthetistLimit=2):
    """检查每个时段(列)中需麻醉师的手术数是否≤限制"""
    # 遍历9个时段(行索引)
    for slot_idx in range(9):
        # 提取该时段在3个手术室中的手术记录
        comparison_array = [
            timetable[0][slot_idx],
            timetable[1][slot_idx],
            timetable[2][slot_idx]
        ]
        anaesthetist_count = sum(
            1 for surgery in comparison_array 
            if surgery["requires_anaesthetist"] == "Yes"
        )
        if anaesthetist_count > anaesthetistLimit:
            print(f"Constraint breached: {anaesthetist_count} anaesthetists required (limit: {anaesthetistLimit})")
            return False
    return True

# 主循环:安全、可终止的生成-验证流程
timetable = RandomiseTimetable(surgeryData)  # 初始化
max_attempts = 1000
attempt = 0
while not AnaesthetistsWithinLimit(timetable, 2) and attempt = max_attempts:
    raise RuntimeError("Failed to generate a valid timetable within maximum attempts.")

FitnessFunction(timetable, True)  # 进入后续优化步骤

? 关键改进点总结

  • 状态隔离:RandomiseTimetable 不再接收 timetable 参数,彻底避免副作用;
  • 明确所有权:每次调用返回全新对象,主逻辑通过赋值控制当前有效解;
  • 防死循环机制:添加 max_attempts 保护,避免因数据分布问题(如CSV中“Yes”比例过高)导致无限等待;
  • 代码健壮性:约束检查中使用 sum() + 生成器表达式替代嵌套循环,更简洁且不易出错。

这种设计不仅解决了当前问题,也为后续引入更复杂的约束(如医生排班、设备冲突等)提供了清晰、可扩展的架构基础。