案例: 合并表格使用 Dict

(date: 2025-11-18)

学习建议:建议先完成 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 总表

期望:

{
    S001: {'姓名': '张三', '语文': 85, '数学': 90, '英语': 88}
    S002: {'姓名': '李四', '语文': 92, '数学': 87, '英语': 85}
    S003: {'姓名': '王五', '语文': 78, '数学': 85, '英语': 80}
}

先处理语文

# 创建空字典来存储合并后的数据
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}")

接着处理数学

# 处理数学成绩
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}")

打印结果

合并后的学生成绩表
S001: {'姓名': '张三', '语文': 85, '数学': 90, '英语': 88}
S002: {'姓名': '李四', '语文': 92, '数学': 87, '英语': 85}
S003: {'姓名': '王五', '语文': 78, '数学': 85, '英语': 80}

有两个主要问题:

  1. [homework] 处理3们不同学科时,代码是相同的,如何合并?

  2. 最后的结果和要求有所不同,如何改进?

字典转列表

你说得非常对!这部分跨度确实太大了。直接从"先处理语文→再处理数学"的渐进式教学,突然跳到了一个复杂的、用列表存储的字典方案,逻辑转换太突兀。

让我重新设计这个过渡:

改进方案:渐进式教学

阶段1:先用字典完成数据合并(已完成)

# 这是我们前面已经完成的字典结构
student_scores = {
    'S001': {'姓名': '张三', '语文': 85, '数学': 90, '英语': 88},
    'S002': {'姓名': '李四', '语文': 92, '数学': 87, '英语': 85},
    'S003': {'姓名': '王五', '语文': 78, '数学': 85, '英语': 80}
}

阶段2:分析字典的局限性,引出列表需求

讨论问题

  • 字典虽然查询方便,但最终我们需要表格形式的结果

  • 很多场景下(如导出CSV、显示表格)需要列表结构

  • 如何把字典转换成期望的列表格式?

阶段3:手动转换示范

# 方法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:从字典自动转换

# 方法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:介绍"列表存储"方案

引出思路:"其实,我们也可以从一开始就用列表来存储,避免最后的转换..."

# 方法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:逐步完善多科目处理

# 接着处理数学
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:最终优化成完整方案

# 完整的优化方案(现在学生已经理解每一步了)
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())

这样的分解是不是更符合学习逻辑?从"为什么需要转换" → "如何手动转换" → "如何自动转换" → "如何从一开始就用目标格式",让学生理解每种方案的思考过程。

封装:直接合并成列表

# 创建字典来存储学生信息
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. 可读性:键名具有语义信息