在第八章内容的结尾,我们给了一份学生成绩模拟数据,并希望你能利用第八章聊到的数据结构来解决三个问题,我们先来回忆一下数据和问题:
# 成绩原始数据:每个元组格式为 (学生ID, 姓名, 科目, 分数, 考试类型(期中/期末))[ (101, "张三", "数学", 92, "期中"), (101, "张三", "语文", 85, "期中"), (101, "张三", "英语", 88, "期中"), (101, "张三", "数学", 95, "期末"), (101, "张三", "语文", 89, "期末"), (101, "张三", "英语", 90, "期末"), (102, "李四", "数学", 78, "期中"), (102, "李四", "语文", 94, "期中"), (102, "李四", "英语", 80, "期中"), (102, "李四", "数学", 82, "期末"), (102, "李四", "语文", 96, "期末"), (102, "李四", "英语", 85, "期末"), (103, "王五", "数学", 65, "期中"), (103, "王五", "语文", 75, "期中"), (103, "王五", "英语", 70, "期中"), (103, "王五", "数学", 72, "期末"), (103, "王五", "语文", 80, "期末"), (103, "王五", "英语", 78, "期末"), (104, "赵六", "数学", 98, "期中"), (104, "赵六", "语文", 88, "期中"), (104, "赵六", "英语", 95, "期中"), (104, "赵六", "数学", 96, "期末"), (104, "赵六", "语文", 90, "期末"), (104, "赵六", "英语", 97, "期末"), (105, "孙七", "数学", 85, "期中"), (105, "孙七", "语文", 82, "期中"), (105, "孙七", "英语", 86, "期中"), (105, "孙七", "数学", 88, "期末"), (105, "孙七", "语文", 84, "期末"), (105, "孙七", "英语", 89, "期末")]处理这份数据,希望你做到以下几点:1)找出所有考试的科目名称2)统计每个学生每科期中、期末的平均分,所有科目的总分(期中+期末),个人总成绩排名3)找出分数出现次数最多的前5个
对这三个问题,我们有一个基本的思路:
第一个问题,要找出考试科目的名称,从数据中我们可以看出,科目的名称是存在重复的,所以对科目进行去重就可以,我们可以用集合来实现。
第二个问题,我们需要展示的内容至少有四部分,即期中平均分、期末平均分、科目总分、个人成绩排名,这个我们可以用字典结构来展示,那么处理数据的过程就可以用namedtuple,defaultdict数据结构。
第三个问题,是想要找分数出现的频次,可以用Counter来解决。
好了,根据这个大致的思路,我们来写一下代码:
from collections import namedtuple, defaultdict, Counterdata = [ (101, "张三", "数学", 92, "期中"), (101, "张三", "语文", 85, "期中"), (101, "张三", "英语", 88, "期中"), (101, "张三", "数学", 95, "期末"), (101, "张三", "语文", 89, "期末"), (101, "张三", "英语", 90, "期末"), (102, "李四", "数学", 78, "期中"), (102, "李四", "语文", 94, "期中"), (102, "李四", "英语", 80, "期中"), (102, "李四", "数学", 82, "期末"), (102, "李四", "语文", 96, "期末"), (102, "李四", "英语", 85, "期末"), (103, "王五", "数学", 65, "期中"), (103, "王五", "语文", 75, "期中"), (103, "王五", "英语", 70, "期中"), (103, "王五", "数学", 72, "期末"), (103, "王五", "语文", 80, "期末"), (103, "王五", "英语", 78, "期末"), (104, "赵六", "数学", 98, "期中"), (104, "赵六", "语文", 88, "期中"), (104, "赵六", "英语", 95, "期中"), (104, "赵六", "数学", 96, "期末"), (104, "赵六", "语文", 90, "期末"), (104, "赵六", "英语", 97, "期末"), (105, "孙七", "数学", 85, "期中"), (105, "孙七", "语文", 82, "期中"), (105, "孙七", "英语", 86, "期中"), (105, "孙七", "数学", 88, "期末"), (105, "孙七", "语文", 84, "期末"), (105, "孙七", "英语", 89, "期末")]# 利用namedtuple将元组语义化GradeReport = namedtuple('GradeReport', ['id', 'name', 'course', 'score', 'type'])grade_report = [GradeReport(*item) for item in data]# print(score_list)# 利用集合去重获取所有的考试科目course_names = {s.course for s in grade_report}print(course_names)# 利用defaultdict来统计每个学生的期中、期末平均分,所有科目总分(期中+期末)、个人总成绩排名# 遍历grade_report,按照id进行分组,并填充基本的信息stu_info: dict[int, dict] = defaultdict(lambda: { 'name': '', 'mid_scores': [], 'final_scores': [], 'total_score': 0})for g in grade_report: sid = g.id stu_info[sid]['name'] = g.name if g.type == '期中': stu_info[sid]['mid_scores'].append(g.score) elif g.type == '期末': stu_info[sid]['final_scores'].append(g.score)# print(dict(stu_info))results = []for sid, info in stu_info.items(): # 计算期中平均分,保留一位小数 mid_avg = round(sum(info['mid_scores']) / len(info['mid_scores']), 1) # 计算期末平均分,保留一位小数 final_avg = round(sum(info['final_scores']) / len(info['final_scores']), 1) # 计算总分=期中总分+期末总分 total_score = sum(info['mid_scores']) + sum(info['final_scores']) res = { 'id': sid, 'name': info['name'], 'mid_avg': mid_avg, 'final_avg': final_avg, 'total_score': total_score, 'rank': 0 # 后续计算 } results.append(res)# 接下来按照总分排名,先排序,再为rank赋值sorted_results = sorted(results, key=lambda x: x['total_score'], reverse=True)for rank, stu in enumerate(sorted_results, 1): stu['rank'] = rankprint(sorted_results)# 找出出现频次排名前五的分数scores = [s.score for s in grade_report]counter = Counter(scores)top5 = counter.most_common(5)print(top5)以上是我给出的练习示例代码,你在练习时遇到了哪些问题?我们可以一起来讨论。