如何在Python中高效分组课程对象的学生分数数据
高效实现课程分数数据按学生-分数分组的方案
这个需求本质是多层分组聚合:先按学生分组,再按分数分组,最后收集对应分数的课程列表。下面给出两种高效的实现方式,都是线性时间复杂度,处理大量数据也没问题。
准备工作:模拟课程对象
首先我们先把你的课程对象用代码模拟出来,方便测试:
class Course: def __init__(self, name, records): self.name = name self.records = records # 示例课程 c1 = Course("c1", {"student1": 100, "student2": 90}) c2 = Course("c2", {"student1": 100, "student2": 40, "student3": 80}) # 把所有课程放到一个列表里统一处理 courses = [c1, c2]
方案一:用collections.defaultdict简化代码(推荐)
利用Python标准库的defaultdict可以省去手动判断键是否存在的繁琐步骤,代码简洁且高效:
from collections import defaultdict # 初始化嵌套字典:学生 -> {分数: [课程名称列表]} result = defaultdict(lambda: defaultdict(list)) for course in courses: course_name = course.name # 遍历当前课程的所有学生分数记录 for student, score in course.records.items(): # 直接追加课程名称,defaultdict会自动初始化不存在的键 result[student][score].append(course_name) # 可选:将嵌套的defaultdict转换为普通字典(如果需要严格匹配目标格式) final_result = {student: dict(scores) for student, scores in result.items()} print(final_result)
输出结果完全符合你的需求:
{ 'student1': {100: ['c1', 'c2']}, 'student2': {90: ['c1'], 40: ['c2']}, 'student3': {80: ['c2']} }
方案说明
defaultdict(lambda: defaultdict(list))创建了一个两层的默认字典:第一层的键是学生名,对应的值是另一个默认字典;第二层的键是分数,对应的值是列表,用来存课程名称。- 整个过程是线性遍历,每个分数记录只处理一次,时间复杂度为O(N)(N是所有课程的学生记录总数),效率拉满。
方案二:不依赖标准库,手动实现字典初始化
如果不想导入collections,可以手动判断键是否存在,逻辑和方案一完全一致,只是代码稍长:
result = {} for course in courses: course_name = course.name for student, score in course.records.items(): # 初始化学生对应的字典 if student not in result: result[student] = {} # 初始化分数对应的课程列表 if score not in result[student]: result[student][score] = [] # 添加当前课程名称 result[student][score].append(course_name) print(result)
这个版本同样是O(N)的时间复杂度,适合对依赖有严格限制的场景。
内容的提问来源于stack exchange,提问作者JRR
相关产品推荐
相关产品推荐

