首页 > 解决方案 > 使用嵌入在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)]}]

标签: python

解决方案


这对于初学者课程来说是一项艰巨的任务。困难在于 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 函数)更易于阅读、编写和理解。以我最近对这个问题的回答为例。


推荐阅读