python - 使用嵌入在python字典列表中的元组列表
问题描述
我正在上一门编码课程,我似乎无法将我所学的基础知识转化为一个工作程序,其中包含如此复杂的列表。我应该使用什么功能来做到这一点?
在这一点上,我们还没有讨论导入任何额外的特性(numpy 等),我知道人们经常使用 lambda(虽然我并不真正理解它的作用),但这在本课程中没有介绍。
#This is an example of the structure of a student dictionary
#They have an id number
#They have a first name, last name and a list of assignments
#Assignments are tuples of an assignment name and grade
#The grade is a 4 point scale from 0 to 4
'''
student_list = [{'id': 12341, 'first_name': 'Alice', 'last_name': 'Anderson',
'assignments': [('assignment_1', 0), ('assignment_2', 2), ('assignment_3', 4)]},
{'id': 12342, 'first_name': 'Boris', 'last_name': 'Bank',
'assignments': [('assignment_1', 1), ('assignment_2', 3), ('assignment_3', 0)]},
{'id': 12343, 'first_name': 'Carl', 'last_name': 'Cape',
'assignments': [('assignment_1', 2), ('assignment_2', 4), ('assignment_3', 1)]},
{'id': 12344, 'first_name': 'Didi', 'last_name': 'Dawson',
'assignments': [('assignment_1', 3), ('assignment_2', 0), ('assignment_3', 2)]},
{'id': 12345, 'first_name': 'Ed', 'last_name': 'Enders',
'assignments': [('assignment_1', 4), ('assignment_2', 1), ('assignment_3', 3)]}]
#This function should return a list of the n student dictionaries with the
#highest grades on the assignment passed in as assignment name
#If there is a tie then it is broken by returning the student(s) with the
#lowest id number(s)
def highest_n_grades(students, assignment_name, n):
编辑
对不起,我不想得到答案。我看那看起来如何。我觉得我已经写出并删除了一百万件事,这是我的问题。我什至开始都遇到了麻烦。
我希望在正确的方向上找到一个点,也许哪些命令可以获取最高分等。到目前为止,我真正拥有的只是:
def highest_n_grades(student_list):
for s in student_list:
for assignment_name, grade in s['assignments']:
if int(grade) >= 4:
print(assignment_name, grade)
highest_n_grades(student_list)
但我知道这甚至不能让我真正开始。它没有三个输入,也不是在寻找最大值,而是在寻找手动输入的值 4,甚至还没有接近与学生姓名绑定或制作另一个列表。
编辑 2
还尝试了一个错误,我试图对字典而不是列表进行排序。
def highest_n_grades(student_list, assignment_name):
for s in student_list:
for assignment_name in s['assignments'][1]:
s['assignments'][1] = assignment_name
s.sort(key=assignment_name)
print(student_list)
highest_n_grades(student_list, assignment_name='assignment_1' )
编辑 3
好吧,我可能取得了一些进展?
newlist2 = sorted(newlist, key=lambda k: k['assignments'][0], reverse = True)
newlist3 = sorted(newlist, key=lambda k: k['assignments'][1], reverse = True)
newlist4 = sorted(newlist, key=lambda k: k['assignments'][2], reverse = True)
这些似乎是按任务排序的。我不明白 lambda 在做什么,但我至少可以生成一个最高等级的列表。我认为这是一个婴儿步骤。
编辑 4
这是我创建的一个函数。它似乎得到了我想要的东西,它输出了最高的 3 名学生,但它打印了 5 次?我知道这不是很灵活,但这是一个开始。
def highest_n_grades(student_list, n):
for s in student_list:
newlist = sorted(student_list, key=lambda k: k['assignments'][0], reverse=True)
print(newlist[:n])
highest_n_grades(student_list, 3)
输出:
[{'id': 12345, 'first_name': 'Ed', 'last_name': 'Enders', 'assignments': [('assignment_1', 4), ('assignment_2', 1), ('assignment_3', 3)]}, {'id': 12344, 'first_name': 'Didi', 'last_name': 'Dawson', 'assignments': [('assignment_1', 3), ('assignment_2', 0), ('assignment_3', 2)]}, {'id': 12343, 'first_name': 'Carl', 'last_name': 'Cape', 'assignments': [('assignment_1', 2), ('assignment_2', 4), ('assignment_3', 1)]}]
[{'id': 12345, 'first_name': 'Ed', 'last_name': 'Enders', 'assignments': [('assignment_1', 4), ('assignment_2', 1), ('assignment_3', 3)]}, {'id': 12344, 'first_name': 'Didi', 'last_name': 'Dawson', 'assignments': [('assignment_1', 3), ('assignment_2', 0), ('assignment_3', 2)]}, {'id': 12343, 'first_name': 'Carl', 'last_name': 'Cape', 'assignments': [('assignment_1', 2), ('assignment_2', 4), ('assignment_3', 1)]}]
[{'id': 12345, 'first_name': 'Ed', 'last_name': 'Enders', 'assignments': [('assignment_1', 4), ('assignment_2', 1), ('assignment_3', 3)]}, {'id': 12344, 'first_name': 'Didi', 'last_name': 'Dawson', 'assignments': [('assignment_1', 3), ('assignment_2', 0), ('assignment_3', 2)]}, {'id': 12343, 'first_name': 'Carl', 'last_name': 'Cape', 'assignments': [('assignment_1', 2), ('assignment_2', 4), ('assignment_3', 1)]}]
[{'id': 12345, 'first_name': 'Ed', 'last_name': 'Enders', 'assignments': [('assignment_1', 4), ('assignment_2', 1), ('assignment_3', 3)]}, {'id': 12344, 'first_name': 'Didi', 'last_name': 'Dawson', 'assignments': [('assignment_1', 3), ('assignment_2', 0), ('assignment_3', 2)]}, {'id': 12343, 'first_name': 'Carl', 'last_name': 'Cape', 'assignments': [('assignment_1', 2), ('assignment_2', 4), ('assignment_3', 1)]}]
[{'id': 12345, 'first_name': 'Ed', 'last_name': 'Enders', 'assignments': [('assignment_1', 4), ('assignment_2', 1), ('assignment_3', 3)]}, {'id': 12344, 'first_name': 'Didi', 'last_name': 'Dawson', 'assignments': [('assignment_1', 3), ('assignment_2', 0), ('assignment_3', 2)]}, {'id': 12343, 'first_name': 'Carl', 'last_name': 'Cape', 'assignments': [('assignment_1', 2), ('assignment_2', 4), ('assignment_3', 1)]}]
解决方案
这对于初学者课程来说是一项艰巨的任务。困难在于 lambdas、多键排序、列表、列表切片和元组、字典,甚至是有序与无序的数据类型。我已经用 Python 编程了 10 年,但并不觉得它很简单。
lambda 是您动态定义的一个小函数。sorted()
接受一个函数作为它的第二个参数。它需要为每个学生调用这个函数来生成一个排序键。sort 函数比较两个学生的排序键来决定哪个学生排在第一位。
开始使用 lambda 的一个好地方是记住:
id_key = lambda x: x[0]
相当于:
def id_key(x):
return x[0]
此外
sorted(students, key=lambda x: x[0])
相当于:
sorted(student, key=id_key)
为了对多个值进行排序,我会查看stable sorts 及其 properties。稳定的排序算法非常适合对多个值进行排序。大多数 Python 排序函数都是“稳定的”。
这是使用当前结构的解决方案:
def sort_by_grade_then_id(grades):
# sort (id, grade) tuples high grades, low ids first
sorted_by_id = sorted(grades, key=lambda student: student[0])
sorted_by_id_and_assignment_grade = sorted(sorted_by_id,
key=lambda student: student[1], reverse=True)
return sorted_by_id_and_assignment_grade
def highest_n_grades(students, assignment_name, n):
grades = []
for student in students:
for assignment, grade in student['assignments']:
if assignment_name == assignment:
grades.append((student['id'], grade))
return sort_by_grade_then_id(grades)[:n]
>>> print(highest_n_grades(student_list, 'assignment_2', 2))
[(12343, 4), (12342, 3)]
但是,如果您现在想要学生的姓名而不是他/她的身份证,则必须进行另一次连续搜索才能得到它。
作为一种不同的方法,以下将基于列表的原始学生数据库复制到基于字典的数据库中。
from copy import copy
students_dict = {student['id']: student for student in copy(student_list)}
for student in students_dict.values():
student['assignments'] = dict(student['assignments'])
列出最高成绩变为:
def highest_n_grades_dict(students, assignment_name, n):
grades = [
(id, student['assignments'][assignment_name])
for id, student
in students.items()
]
return sort_by_grade_then_id(grades)[:n]
只有几个学生没关系,但如果你有很多学生和很多作业,这个新版本会更快。您现在也可以使用学生数据库查找资料,而不必搜索和匹配。
举个例子:
print('Highest grades dict version...')
grades = highest_n_grades_dict(students_dict, 'assignment_2', 2)
print(grades)
print("...and dict structure easily allows us to get other student details")
names_and_grades = [
(students_dict[id]['first_name'] + ' ' + students_dict[id]['last_name'], grade)
for id, grade
in grades]
print(names_and_grades)
>>> python grades.py
Highest grades dict version...
[(12343, 4), (12342, 3)]
...and dict structure easily allows us to get other student details
[('Carl Cape', 4), ('Boris Bank', 3)]
旁注:如果您经常处理元组,您可能会对命名元组感兴趣,因为它们通常使与元组相关的代码(包括 lambda 函数)更易于阅读、编写和理解。以我最近对这个问题的回答为例。
推荐阅读
- entity-framework - 使用 HasData 仅在 OnModelCreating(...) 内迁移时播种数据
- streaming - 为什么这些 GST-Compositor caps 过滤会导致图像阴影?
- javascript - Javascript reducer,如何停止 && 运算符重置值?
- typescript - ESLint:解析错误:无法在 WSL2 上的 WebStorm IDE 上读取文件 tsconfig.json
- sql - 进入sqlplus命令行后无法暂停关闭bash文件
- reactjs - 层次结构 React 项目构建和菜单处理
- c# - WPF 文本框不会触发依赖属性设置器
- python - ImportError:无法从“电报”导入名称“ParseMode”
- c++ - 绑定 Directx 11 中无效的内容时 GPU 崩溃
- c++ - std::async 和 std::lock_guard 的问题 - C++ 中的不同增量值