iT邦幫忙

1

Python 巢狀字典生成式問題

  • 分享至 

  • xImage
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 這條變數裡面的字典生成式是怎麼跑的@@?看了整個霧煞煞。

ccutmis iT邦高手 2 級 ‧ 2024-08-11 09:08:19 檢舉
https://allaboutdataanalysis.medium.com/9%E5%80%8B%E6%87%89%E7%9F%A5%E6%87%89%E6%9C%83%E7%9A%84%E5%96%AE%E8%A1%8Cpython%E7%A8%8B%E5%BC%8F%E7%A2%BC-8f1f50a67b3a
或 google 搜 'Python 單行程式碼'
froce iT邦大師 1 級 ‧ 2024-08-12 09:27:20 檢舉
1. 這種兩三層的Comprehensions 在實務上盡量不要寫,雖然看得懂但要改不好改。知道有這種寫法就行了
2. Comprehensions 要從右邊讀到左邊
3 . zip要學會。zip很好用
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
熊熊工程師
iT邦研究生 1 級 ‧ 2024-08-11 17:35:53

這段程式碼使用了字典生成式(dictionary comprehension)來生成一個嵌套的字典,包含每個學生在每個科目的成績。

1. 基本結構

grades = {student: {subject: grade for subject, grade in zip(subjects, grades)} for student, grades in zip(students, all_grades)}

這段程式碼其實分為兩層的字典生成式:

  1. 外層字典:這層字典的鍵是學生的名字,值是內層字典(每個學生的成績)。
  2. 內層字典:這層字典的鍵是科目,值是該學生在該科目的成績。

2. zip 函數

zip(subjects, grades)

zip(subjects, grades) 會把 subjectsgrades 這兩個列表「配對」起來。例如,對於 Alice 來說:

  • subjects['Math', 'Science', 'English']
  • grades[85, 90, 88]

zip(subjects, grades) 就會生成一個類似於 [('Math', 85), ('Science', 90), ('English', 88)] 的配對。

3. 內層字典生成式

{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}

4. 外層字典生成式

{student: {subject: grade for subject, grade in zip(subjects, grades)} for student, grades in zip(students, all_grades)}

這裡的 zip(students, all_grades) 會把 studentsall_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}
}
wajika iT邦新手 5 級 ‧ 2024-08-12 10:11:41 檢舉

{'Math': 85, 'Science': 90, 'English': 88} 和('Alice', [85, 90, 88]) 合并吗?

wajika iT邦新手 5 級 ‧ 2024-08-12 10:12:41 檢舉

为什么要外面套一次,里面套一次,从头到尾套一次不就好了嘛

1
Penut Chen
iT邦研究生 5 級 ‧ 2024-08-11 22:23:16

用一般的 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)
}
1
meebox
iT邦新手 3 級 ‧ 2024-08-12 09:31:59

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)

我要發表回答

立即登入回答