students = ['Alice', 'Bob', 'Charlie']
subjects = ['Math', 'Science', 'English']
all_grades = [
[85, 90, 88], # Alice
[78, 83, 82], # Bob
[92, 88, 91] # Charlie
]
grades = {student: {subject: grade for subject, grade in zip(subjects, grades)} for student, grades in zip(students, all_grades)}
print(grades)
唯一想問的是 grades 這條變數裡面的字典生成式是怎麼跑的@@?看了整個霧煞煞。
這段程式碼使用了字典生成式(dictionary comprehension)來生成一個嵌套的字典,包含每個學生在每個科目的成績。
grades = {student: {subject: grade for subject, grade in zip(subjects, grades)} for student, grades in zip(students, all_grades)}
這段程式碼其實分為兩層的字典生成式:
zip
函數zip(subjects, grades)
zip(subjects, grades)
會把 subjects
和 grades
這兩個列表「配對」起來。例如,對於 Alice
來說:
subjects
是 ['Math', 'Science', 'English']
grades
是 [85, 90, 88]
zip(subjects, grades)
就會生成一個類似於 [('Math', 85), ('Science', 90), ('English', 88)]
的配對。
{subject: grade for subject, grade in zip(subjects, grades)}
這個生成式會對 zip(subjects, grades)
的每一對 (subject, grade)
生成一個字典條目。對於 Alice
:
'Math': 85
'Science': 90
'English': 88
這樣,內層字典就會變成 {'Math': 85, 'Science': 90, 'English': 88}
。
{student: {subject: grade for subject, grade in zip(subjects, grades)} for student, grades in zip(students, all_grades)}
這裡的 zip(students, all_grades)
會把 students
和 all_grades
配對起來:
('Alice', [85, 90, 88])
('Bob', [78, 83, 82])
('Charlie', [92, 88, 91])
然後,對於每一對 (student, grades)
,外層字典生成式會以 student
為鍵,並將內層字典(每個科目的成績)作為對應的值。最終生成的 grades
字典如下:
{
'Alice': {'Math': 85, 'Science': 90, 'English': 88},
'Bob': {'Math': 78, 'Science': 83, 'English': 82},
'Charlie': {'Math': 92, 'Science': 88, 'English': 91}
}
用一般的 For 迴圈來寫,會長這樣:
grade_v1 = dict()
for student, grades in zip(students, all_grades):
grade_v1[student] = dict()
for subject, grade in zip(subjects, grades):
grade_v1[student][subject] = grade
print(grade_v1)
其中,第二層迴圈可以用單行寫法 aka Comprehensions 來簡化:
grade_v1[student] = dict()
for subject, grade in zip(subjects, grades):
grade_v1[student][subject] = grade
# 等同於
grade_v1[student] = {subject: grade for subject, grade in zip(subjects, grades)}
用同樣的方式來簡化最外層的迴圈,就會變成你看到的那樣了:
grade_v2 = {
student: {subject: grade for subject, grade in zip(subjects, grades)}
for student, grades in zip(students, all_grades)
}
comprehension 很像是一般迴圈的倒裝句, 你只要依序一層層把它變回一般的迴圈就很容易理解:
student_grades = {}
for student, grades in zip(students, all_grades):
# 這會依序取得每一個學生的所有分數
# 'Alice' -> [85, 90, 88]
# 'Bob' -> [78, 83, 82]
# 'Charlie' -> [92, 88, 91]
subject_grades = {}
for subject, grade in zip(subjects, grades):
# 這會依序取得
# 'Math' -> 85
# 'Science' -> 90
# 'English' -> 88
# 'Math' -> 78
# 'Science' -> 83
# 'English' -> 82
# 'Math' -> 92
# 'Science' -> 88
# 'English' -> 91
subject_grades[subject]=grade
student_grades[student] = subject_grades
grades = student_grades
print(grades)