--- tid: 32impo title: 案例: 合并表格使用 Dict --- # 案例: 合并表格使用 Dict (date: 2025-11-18) **学习建议**:建议先完成 [`dict-tutorial-1.md`](dict-tutorial-1.md) 的基础学习,再学习本案例。 提出问题,需求分析,技术方案,掌握工具,实践验证——五大环节,完成一个案例。 **学习目标**: - 理解列表和字典在数据处理中的不同应用场景 - 掌握将列表数据转换为字典的方法 - 学会使用字典进行高效的数据合并操作 - 理解不同数据结构的性能特点 ## 问题与分析 ### 原数据 ``` # 语文老师提供 chinese_scores = [["张三", "S001", 85], ["李四", "S002", 92], ["王五", "S003", 78]] # 数学老师提供 math_scores = [["张三", "S001", 90], ["李四", "S002", 87], ["王五", "S003", 85]] # 英语老师提供 english_scores = [["S001", "张三", 88], ["S002", "李四", 85], ["S003", "王五", 80]] ``` ### 期望的结果 期望得到一个合并后的成绩表,包含每个学生的所有科目成绩: ``` [ ["学号", "姓名", "语文", "数学", "英语"], ["S001", "张三", 85, 90, 88], ["S002", "李四", 92, 87, 85], ["S003", "王五", 78, 85, 80] ] ``` ## 整合数据 ### 输入为整齐的三个数据表(准备) ``` chinese = [ ['S001', '张三', 85], ['S002', '李四', 92], ['S003', '王五', 78] ] math = [ ['S001', '张三', 90], ['S002', '李四', 87], ['S003', '王五', 85] ] english = [ ['S001', '张三', 88], ['S002', '李四', 85], ['S003', '王五', 80] ] ``` ### 合并成 dict 总表 期望: ```python { S001: {'姓名': '张三', '语文': 85, '数学': 90, '英语': 88} S002: {'姓名': '李四', '语文': 92, '数学': 87, '英语': 85} S003: {'姓名': '王五', '语文': 78, '数学': 85, '英语': 80} } ``` #### 先处理语文 ```python # 创建空字典来存储合并后的数据 student_scores = {} # 处理语文成绩 for record in chinese: student_id, name, score = record student_scores[student_id] = { '姓名': name, '语文': score } for student_id, scores in student_scores.items(): print(f"{student_id}: {scores}") ``` #### 接着处理数学 ```python # 处理数学成绩 for record in math: student_id, name, score = record # 如果该学生已存在,只更新数学成绩;如果不存在,创建新记录 if student_id in student_scores: student_scores[student_id]['数学'] = ... else: student_scores[student_id] = { '姓名': name, '数学': ... } for student_id, scores in student_scores.items(): print(f"{student_id}: {scores}") ``` #### 再接着处理英语成绩 ``` # 处理英语成绩 for record in english: student_id, name, score = record if student_id in student_scores: student_scores[student_id]['英语'] = score else: student_scores[student_id] = { '姓名': name, ...: ... } # 打印合并后的结果 print("合并后的学生成绩表:") for student_id, scores in student_scores.items(): print(f"{student_id}: {scores}") ``` #### 打印结果 ```python 合并后的学生成绩表: S001: {'姓名': '张三', '语文': 85, '数学': 90, '英语': 88} S002: {'姓名': '李四', '语文': 92, '数学': 87, '英语': 85} S003: {'姓名': '王五', '语文': 78, '数学': 85, '英语': 80} ``` 有两个主要问题: 1. [homework] 处理3们不同学科时,代码是相同的,如何合并? 2. 最后的结果和要求有所不同,如何改进? ### 字典转列表 你说得非常对!这部分跨度确实太大了。直接从"先处理语文→再处理数学"的渐进式教学,突然跳到了一个复杂的、用列表存储的字典方案,逻辑转换太突兀。 让我重新设计这个过渡: ## 改进方案:渐进式教学 ### 阶段1:先用字典完成数据合并(已完成) ```python # 这是我们前面已经完成的字典结构 student_scores = { 'S001': {'姓名': '张三', '语文': 85, '数学': 90, '英语': 88}, 'S002': {'姓名': '李四', '语文': 92, '数学': 87, '英语': 85}, 'S003': {'姓名': '王五', '语文': 78, '数学': 85, '英语': 80} } ``` ### 阶段2:分析字典的局限性,引出列表需求 **讨论问题**: - 字典虽然查询方便,但最终我们需要表格形式的结果 - 很多场景下(如导出CSV、显示表格)需要列表结构 - 如何把字典转换成期望的列表格式? ### 阶段3:手动转换示范 ```python # 方法1:手动构建(理解逻辑) header = ["学号", "姓名", "语文", "数学", "英语"] result = [header] # 先放表头 # 手动添加第一条数据 result.append(["S001", "张三", 85, 90, 88]) result.append(["S002", "李四", 92, 87, 85]) result.append(["S003", "王五", 78, 85, 80]) print("手动构建的结果:") for row in result: print(row) ``` ### 阶段4:从字典自动转换 ```python # 方法2:从字典自动转换 result_auto = [header] for student_id, scores in student_scores.items(): row = [ student_id, scores['姓名'], scores['语文'], scores['数学'], scores['英语'] ] result_auto.append(row) print("自动转换的结果:") for row in result_auto: print(row) ``` ### 阶段5:介绍"列表存储"方案 **引出思路**:"其实,我们也可以从一开始就用列表来存储,避免最后的转换..." ```python # 方法3:从一开始就用列表存储(你原来那部分的简化版) student_dict_list = {} # 先只处理一个科目来演示 for record in chinese: student_id, name, score = record student_dict_list[student_id] = [student_id, name, score, 0, 0] # 数学英语先填0 print("处理语文后的中间结果:") for student_id, row in student_dict_list.items(): print(f"{student_id}: {row}") ``` ### 阶段6:逐步完善多科目处理 ```python # 接着处理数学 for record in math: student_id, name, score = record if student_id in student_dict_list: student_dict_list[student_id][3] = score # 更新数学成绩 else: student_dict_list[student_id] = [student_id, name, 0, score, 0] print("处理数学后的结果:") for student_id, row in student_dict_list.items(): print(f"{student_id}: {row}") # 最后处理英语(让学生自己尝试) ``` ### 阶段7:最终优化成完整方案 ```python # 完整的优化方案(现在学生已经理解每一步了) student_dict_final = {} subjects = [chinese, math, english] for subject_data in subjects: for record in subject_data: student_id, name, score = record if student_id not in student_dict_final: student_dict_final[student_id] = [student_id, name, 0, 0, 0] if subject_data == chinese: student_dict_final[student_id][2] = score elif subject_data == math: student_dict_final[student_id][3] = score elif subject_data == english: student_dict_final[student_id][4] = score # 最终转换 final_result = [header] + list(student_dict_final.values()) ``` 这样的分解是不是更符合学习逻辑?从"为什么需要转换" → "如何手动转换" → "如何自动转换" → "如何从一开始就用目标格式",让学生理解每种方案的思考过程。 ## 封装:直接合并成列表 ```python # 创建字典来存储学生信息 student_dict = {} # 处理所有科目数据 subjects = [chinese, math, english] for subject_data in subjects: for record in subject_data: student_id, name, score = record if student_id not in student_dict: # 初始化学生信息:学号,姓名,语文,数学,英语 student_dict[student_id] = [student_id, name, 0, 0, 0] # 根据当前科目确定成绩位置 if subject_data == chinese: student_dict[student_id][2] = score # 语文成绩 elif subject_data == math: student_dict[student_id][3] = score # 数学成绩 elif subject_data == english: student_dict[student_id][4] = score # 英语成绩 # 转换为最终的列表格式 merged_list = list(student_dict.values()) # 打印结果 print("合并后的学生成绩表:") print("学号\t姓名\t语文\t数学\t英语") for student in merged_list: print(f"{student[0]}\t{student[1]}\t{student[2]}\t{student[3]}\t{student[4]}") ``` ## Dict 与 List 比较 使用字典可以更优雅地解决这个问题。字典的优势在于: 1. **快速查找**:通过键直接访问,时间复杂度 O(1) 2. **灵活性**:不需要关心数据顺序 3. **容错性**:可以处理缺失数据 4. **可读性**:键名具有语义信息