Ga naar hoofdinhoud

11c Geneste dictionaries

Een dictionary koppelt een sleutel aan een waarde. Tot nu toe was die waarde een getal of een tekst. Maar een waarde mag alles zijn: ook een lijst, of weer een dictionary. Zo bewaar je per leerling meerdere gegevens in één variabele:

klas = {
"Sara": {"leeftijd": 15, "cijfers": [7, 8, 6]},
"Alex": {"leeftijd": 14, "cijfers": [9, 5, 8]},
}

print(klas["Sara"])

Uitvoer:

{'leeftijd': 15, 'cijfers': [7, 8, 6]}

klas["Sara"] is zelf een dictionary. Zo'n dictionary in een dictionary heet genest.

Opzoeken met twee sleutels​

Wil je alleen de leeftijd van Sara, dan zet je de tweede sleutel er direct achter:

print(klas["Sara"]["leeftijd"]) # 15
print(klas["Alex"]["cijfers"]) # [9, 5, 8]
print(klas["Alex"]["cijfers"][0]) # 9

Lees het van links naar rechts: eerst zoek je "Alex" op in klas, in wat daaruit komt zoek je "cijfers" op, en van die lijst neem je plek 0.

Aanpassen en toevoegen​

Aanpassen gaat op dezelfde manier. Aan de lijst met cijfers voeg je met .append() een cijfer toe, en een nieuwe leerling is een nieuwe sleutel met een eigen dictionary:

klas = {
"Sara": {"leeftijd": 15, "cijfers": [7, 8, 6]},
"Alex": {"leeftijd": 14, "cijfers": [9, 5, 8]},
}

klas["Sara"]["leeftijd"] = 16
klas["Sara"]["cijfers"].append(9)
klas["Noor"] = {"leeftijd": 15, "cijfers": []}

print(klas["Sara"])
print(len(klas))

Uitvoer:

{'leeftijd': 16, 'cijfers': [7, 8, 6, 9]}
3

Door geneste gegevens loopen​

Met .items() krijg je per ronde de naam én de dictionary met gegevens. Daaruit haal je met een tweede sleutel wat je nodig hebt:

klas = {
"Sara": {"leeftijd": 15, "cijfers": [7, 8, 6]},
"Alex": {"leeftijd": 14, "cijfers": [9, 5, 8]},
}

for naam, gegevens in klas.items():
gemiddelde = sum(gegevens["cijfers"]) / len(gegevens["cijfers"])
print(f"{naam} ({gegevens['leeftijd']}): gemiddeld {gemiddelde:.1f}")

Uitvoer:

Sara (15): gemiddeld 7.0
Alex (14): gemiddeld 7.3

Binnen de f-string staat 'leeftijd' tussen enkele aanhalingstekens, omdat de f-string zelf al tussen dubbele staat. :.1f rondt af op één decimaal.

Een lijst van dictionaries​

Andersom kan ook: een lijst waarin elk element een dictionary is. Dat zie je veel, bijvoorbeeld bij een lijst met scores:

scores = [
{"naam": "Sara", "punten": 120},
{"naam": "Alex", "punten": 95},
]

for score in scores:
print(f"{score['naam']}: {score['punten']}")

Uitvoer:

Sara: 120
Alex: 95

Een dictionary gebruik je als je iets opzoekt met een naam, een lijst als de volgorde telt of je alles langsloopt. Geneste gegevens mengen die twee zo dat het bij je gegevens past.


Er gaat iets mis​

Een sleutel op de verkeerde laag

klas = {"Sara": {"leeftijd": 15}}
print(klas["leeftijd"])

Uitvoer:

KeyError: 'leeftijd'

"leeftijd" is geen sleutel van klas, maar van de dictionary in klas["Sara"]. Schrijf eerst de naam, dan de leeftijd: klas["Sara"]["leeftijd"].

Een lijst opzoeken met een tekst

scores = [{"naam": "Sara", "punten": 120}]
print(scores["naam"])

Uitvoer:

TypeError: list indices must be integers or slices, not str

scores is een lijst, en een lijst heeft plekken (0, 1, 2), geen sleutels. Neem eerst een element met scores[0] en zoek daarin ["naam"] op.


Opdracht 11c.1: Boekenkast​

Gegeven is de boekenkast hieronder. Print de schrijver van "De Hobbit" en het aantal bladzijden van "Matilda".

Verwachte uitvoer:

J.R.R. Tolkien
240
boekenkast = {
    "De Hobbit": {"schrijver": "J.R.R. Tolkien", "bladzijden": 320},
    "Matilda": {"schrijver": "Roald Dahl", "bladzijden": 240},
}

# Schrijf hier je code
Klik hier voor een tip.

Eerst de titel van het boek, dan de sleutel binnen dat boek: boekenkast["De Hobbit"]["..."].

Klik hier voor de oplossing.
boekenkast = {
"De Hobbit": {"schrijver": "J.R.R. Tolkien", "bladzijden": 320},
"Matilda": {"schrijver": "Roald Dahl", "bladzijden": 240},
}

print(boekenkast["De Hobbit"]["schrijver"])
print(boekenkast["Matilda"]["bladzijden"])

Uitvoer:

J.R.R. Tolkien
240

Opdracht 11c.2: Een boek erbij​

Voeg aan dezelfde boekenkast een boek naar keuze toe, met schrijver en aantal bladzijden. Print daarna van elk boek een regel zoals De Hobbit, door J.R.R. Tolkien (320 blz.).

boekenkast = {
    "De Hobbit": {"schrijver": "J.R.R. Tolkien", "bladzijden": 320},
    "Matilda": {"schrijver": "Roald Dahl", "bladzijden": 240},
}

# Schrijf hier je code
Klik hier voor een tip.

Een nieuw boek is een nieuwe sleutel: boekenkast["Titel"] = {...}. Loop daarna met for titel, boek in boekenkast.items():.

Klik hier voor de oplossing.
boekenkast = {
"De Hobbit": {"schrijver": "J.R.R. Tolkien", "bladzijden": 320},
"Matilda": {"schrijver": "Roald Dahl", "bladzijden": 240},
}

boekenkast["Koning van Katoren"] = {"schrijver": "Jan Terlouw", "bladzijden": 224}

for titel, boek in boekenkast.items():
print(f"{titel}, door {boek['schrijver']} ({boek['bladzijden']} blz.)")

Uitvoer:

De Hobbit, door J.R.R. Tolkien (320 blz.)
Matilda, door Roald Dahl (240 blz.)
Koning van Katoren, door Jan Terlouw (224 blz.)

Opdracht 11c.3: Wie heeft het hoogste gemiddelde?​

Loop door klas en print de naam van wie het hoogste gemiddelde cijfer heeft.

Verwachte uitvoer:

Noor heeft het hoogste gemiddelde: 8.0
klas = {
    "Sara": {"leeftijd": 15, "cijfers": [7, 8, 6]},
    "Alex": {"leeftijd": 14, "cijfers": [9, 5, 8]},
    "Noor": {"leeftijd": 15, "cijfers": [8, 8, 8]},
}

# Schrijf hier je code
Klik hier voor een tip.

Houd twee variabelen bij: de beste naam tot nu toe en het beste gemiddelde tot nu toe. Begin met het gemiddelde op 0 en vervang beide als je een hoger gemiddelde tegenkomt.

Klik hier voor de oplossing.
klas = {
"Sara": {"leeftijd": 15, "cijfers": [7, 8, 6]},
"Alex": {"leeftijd": 14, "cijfers": [9, 5, 8]},
"Noor": {"leeftijd": 15, "cijfers": [8, 8, 8]},
}

beste_naam = ""
beste_gemiddelde = 0
for naam, gegevens in klas.items():
gemiddelde = sum(gegevens["cijfers"]) / len(gegevens["cijfers"])
if gemiddelde > beste_gemiddelde:
beste_naam = naam
beste_gemiddelde = gemiddelde

print(f"{beste_naam} heeft het hoogste gemiddelde: {beste_gemiddelde:.1f}")

Uitvoer:

Noor heeft het hoogste gemiddelde: 8.0