Python嵌套字典反向过滤 按科目提取参考学生列表
问题场景
现有存储学生考试成绩的嵌套字典dico,外层键为学生姓名,内层键为考试科目、值为对应考试分数,结构示例:
dico = { "Pierre":{ 'Math':16, 'Chimie':9, 'Dessin':18, 'Electronic':20, 'Info':14, }, "Jean":{ 'Physics':10, 'Chimie':20, 'Dessin':13, 'Electronic':16, 'Info':17, }, "Giovani":{ 'Math':16, 'Physics':14, 'Chimie':13, 'Dessin':14, 'Electronic':17, 'Info':12, } # 其余学生数据省略 }
需要实现反向聚合:提取参加每门考试的所有学生,输出「科目: 参考学生列表/集合」格式,预期效果示例:
{ 'Math': ['Pierre', 'Giovani'], 'Physics': ['Jean', 'Giovani'] # 其余科目对应参考学生 }
原有尝试代码运行失败,无法得到预期结果:
exam_set = [{k:v for (k, v) in i.items()} for i in dico if i.get(v) != 0]
原有代码问题
- 外层遍历逻辑错误:直接
for i in dico拿到的i是学生姓名字符串,不是对应科目的成绩字典,无法调用.items()方法 - 变量未定义:判断条件中的
v没有提前声明,会直接抛出名称错误 - 聚合方向错误:代码尝试按学生维度生成字典,和「按科目聚合学生」的需求完全相反
正确实现方案
方法1:基础循环实现(无依赖,可读性最高)
先初始化结果空字典,遍历每个学生的所有考试科目,将学生姓名追加到对应科目的列表中,支持过滤0分(缺考)记录:
result = {} for student, score_map in dico.items(): for subject, score in score_map.items(): # 过滤0分记录,不需要可以删掉这个判断 if score == 0: continue # 科目第一次出现时初始化空列表 if subject not in result: result[subject] = [] result[subject].append(student)
如果需要去重的集合格式,把列表换成集合即可:
result = {} for student, score_map in dico.items(): for subject, score in score_map.items(): if score == 0: continue if subject not in result: result[subject] = set() result[subject].add(student)
方法2:用defaultdict简化逻辑
用标准库collections的defaultdict可以省去手动判断科目是否存在的步骤,代码更简洁:
from collections import defaultdict result = defaultdict(list) for student, score_map in dico.items(): for subject, score in score_map.items(): if score != 0: result[subject].append(student) # 如果需要转成普通原生字典,加一行 result = dict(result) 即可
方法3:字典推导式一行实现
如果偏好推导式写法,可以按科目维度遍历,嵌套推导式筛选对应参考学生:
result = { subject: [ stu for stu, score_map in dico.items() if subject in score_map and score_map[subject] != 0 ] for all_subjects in dico.values() for subject in all_subjects }
内容的提问来源于stack exchange,提问作者Ebone22
相关产品推荐
相关产品推荐

