8.1 Nøstede lister og ordbøker
Lister av lister og ordbøker med sammensatte verdier: to nivåers indeksering og to nivåers løkke — datastrukturen Oppgave 5 bygger på.
Oppgave 5, som er verdt 8–10 poeng — typisk to funksjoner à 4–5 poeng.
Sjangeren er G — skriv en funksjon over en nøstet liste eller ordbok. I tillegg dukker nøstet akkumulering opp som en felle i Oppgave 1, kodesporingen: en løkke inne i en løkke der du må telle rundene nøyaktig.
Dette skal du kunne — bokas midterste av tre prioritetsnivåer. Poengene er
færre enn i den store oppgaven, men de er lette å ta når de to nivåene sitter.
Alt du trenger, kan du fra før. En nøstet liste er en liste der elementene er lister; en nøstet ordbok er en ordbok der verdiene er ordbøker. Løkkene, tellerne og oppslagene er de samme som i del 3 — de kommer bare to lag dypt.
Forkunnskaper — sist du var her
Kapitlet bygger på kap. 3.2 — Ordbøker og
kap. 3.1 — Lister.
De tre tingene du trenger, friskes opp med kjørt kode.
1. Indeksering og løkke over en liste:
tall = [5, 3, 8]
print(tall[0], tall[2], len(tall))
for x in tall:
print(x)Utskrift:
5 8 3
5
3
82. Løkke over en ordbok gir nøklene, ikke verdiene:
d = {"ada": 3, "nora": 7}
for n in d:
print(n, d[n])Utskrift:
ada 3 nora 73. Teller-idiomet, som må opprette nøkkelen først:
d = {}
for navn in ["ada", "nora", "ada"]:
if navn not in d:
d[navn] = 0 d[navn] = d[navn] + 1 print(d)Utskrift:
{'ada': 2, 'nora': 1}Nå legger vi ett lag til utenpå alt dette.
Løkke 1 — Lister av lister (~12 min)
Et treningssenter registrerer deltakere per dag, én liste per uke:
[[14, 9, 20], [11, 0, 7]]
Ytterlista har to elementer — to uker. Hvert av dem er selv en liste med tre tall. Det er alt en nøstet liste er.
En liste der elementene er lister.
uker = [[14, 9, 20], [11, 0, 7]]
print(len(uker))
print(uker[0])
print(len(uker[0]))Utskrift:
2
[14, 9, 20]
3len på ytterlista teller de indre listene, ikke tallene. Her er svaret 2,
ikke 6.
uker[0] gir hele den første indre lista, og den skrives ut med hakeparenteser og komma — akkurat som en vanlig liste.
De indre listene trenger ikke være like lange. [[1, 2], [3], [4, 5, 6]] er en helt gyldig nøstet liste.
To hakeparenteser etter hverandre: den første velger den indre lista, den andre velger et element i den.
uker = [[14, 9, 20], [11, 0, 7]]
print(uker[0][2])
print(uker[1][0])
print(uker[-1][-1])Utskrift:
20
11
7Les fra venstre: uker[0] er første uke, [2] er tredje dag i den.
Rekkefølgen er hele fellen. uker[0][2] og uker[2][0] er to helt ulike
oppslag — og det siste stopper programmet her, fordi ytterlista bare har to elementer.
Negativ indeks virker på begge nivåer, som ellers.
En løkke inne i en løkke. Den ytre gir deg de indre listene, den indre gir deg tallene:
uker = [[14, 9, 20], [11, 0, 7]]
total = 0 for uke in uker:
for tall in uke:
total = total + tall print(total)Utskrift:
61Løkkevariabelen i den ytre løkka er en liste, ikke et tall. Det er den
vanligste lesefeilen: for uke in uker: gir [14, 9, 20] første runde.
Akkumulatoren står utenfor begge løkkene, og resultatet brukes etter begge.
Står total = 0 mellom de to for-linjene, nullstilles den for hver indre liste.
Antall runder til sammen er summen av lengdene til de indre listene — her 3 pluss
3, altså 6.
En nøstet liste holder deltakertall per dag, én indre liste per uke. Skriv kode som summerer alt, teller hvor mange dager som hadde minst ti deltakere, og finner det største tallet.
Tre mønstre fra del 3, hvert av dem med én løkke ekstra utenpå:
uker = [[14, 9, 20], [11, 0, 7], [5, 18]]
total = 0 antall_store = 0 storst = 0 for uke in uker:
for tall in uke:
total = total + tall if tall >= 10:
antall_store = antall_store + 1 if tall > storst:
storst = tall
print("Sum:", total)
print("Minst ti:", antall_store)
print("Storst:", storst)
print("Antall uker:", len(uker))
print("Dager i uke 2:", len(uker[1]))Utskrift:
Sum: 84
Minst ti: 4
Storst: 20
Antall uker: 3
Dager i uke 2: 3Alle tre akkumulatorene står utenfor begge løkkene. Det er det avgjørende:
flytter du total = 0 inn i den ytre løkka, teller den bare den siste uka.
Legg merke til at de indre listene har ulik lengde. Den siste uka har bare to
dager, og løkka bryr seg ikke — for tall in uke: går så mange runder som den lista er lang.
len(uker) er 3, ikke 8. Ytterlista har tre elementer, og hvert av dem er en
liste. Skal du telle tallene, må du gå gjennom begge nivåene — eller summere lengdene.
Slik ville sensor sett på det: i sjanger G ligger poengene på den todelte
løkkestrukturen, på at akkumulatoren står riktig plassert, og på at du bruker riktig nivå i betingelsen. Riktig struktur belønnes selv med en indeksfeil.
(Innstegsoppgave — gjengivelse.) Gitt y = [[3, 8], [1, 4, 9], [7]].
a) Hva er len(y)?
b) Hva er y[1][2]?
c) Hvor mange tall er det til sammen, og hvordan vet du det?
Løkke 2 — Ordbøker med ordbøker inni (~13 min)
Den andre nøstede formen er en ordbok der verdiene er ordbøker:
{"mandag": {"spinning": 14, "yoga": 9}, "tirsdag": {"spinning": 20}}
Ytternøkkelen er dagen, indrenøkkelen er aktiviteten, og verdien er deltakertallet. Det er formen Oppgave 5 oftest bruker.
En ordbok der verdiene selv er ordbøker.
uke = {"mandag": {"spinning": 14, "yoga": 9}, "tirsdag": {"spinning": 20}}
print(len(uke))
print(uke["mandag"])
print(uke["mandag"]["yoga"])Utskrift:
2
{'spinning': 14, 'yoga': 9}
9len på ytterordboka teller ytternøklene — her 2, ikke 3.
uke["mandag"] gir hele den indre ordboka, og den skrives ut med krøllparenteser, enkle anførselstegn rundt nøklene og kolon mellom nøkkel og verdi.
De indre ordbøkene trenger ikke ha de samme nøklene. Tirsdag mangler yoga, og det er helt i orden.
To hakeparenteser etter hverandre, som med lister — men med nøkler i stedet for tall.
uke = {"mandag": {"spinning": 14, "yoga": 9}, "tirsdag": {"spinning": 20}}
print(uke["tirsdag"]["spinning"])Utskrift:
20Begge nivåer kan mangle. uke["onsdag"] stopper programmet medKeyError: 'onsdag', og uke["tirsdag"]["yoga"] stopper medKeyError: 'yoga' — selv om ytternøkkelen finnes.
Derfor må en trygg oppslagsfunksjon sjekke begge nivåene, hver for seg. Det kommer i løkke 3.
Bokas tjuende kodemønster, og det som oftest kreves i Oppgave 5:
d = {}
for ytre, indre, verdi in dataene:
if ytre not in d:
d[ytre] = {}
if indre not in d[ytre]:
d[ytre][indre] = 0 d[ytre][indre] = d[ytre][indre] + verdiBlokken er en mal med plassholdernavn og er merket som ikke-kjørbar.
To sjekker, ikke én. Først må den indre ordboka opprettes, så må den
indre nøkkelen opprettes. Hopper du over den første, stopper programmet medKeyError på ytternøkkelen; hopper du over den andre, stopper det på indrenøkkelen.
Det er feilkode #14 i sin nøstede form, og det er den vanligste feilen i hele kapitlet.
Skal verdien være en liste i stedet for et tall, byttes 0 med [] og+ verdi med .append(verdi) — nøyaktig som i grupperings-idiomet fra
kap. 3.2.
En liste av økter har formen [dag, aktivitet, antall]. Bygg en nøstet ordbok fra dag til aktivitet til samlet antall deltakere.
Oppbyggings-malen satt rett inn, med de to sjekkene:
okter = [["mandag", "spinning", 14],
["mandag", "yoga", 9],
["tirsdag", "spinning", 20],
["mandag", "spinning", 6],
["onsdag", "yoga", 3]]
uke = {}
for o in okter:
dag = o[0]
akt = o[1]
antall = o[2]
if dag not in uke:
uke[dag] = {}
if akt not in uke[dag]:
uke[dag][akt] = 0 uke[dag][akt] = uke[dag][akt] + antall
print(uke)
print(uke["mandag"])
print(uke["mandag"]["spinning"])
print(len(uke), len(uke["mandag"]))Utskrift:
{'mandag': {'spinning': 20, 'yoga': 9}, 'tirsdag': {'spinning': 20}, 'onsdag': {'yoga': 3}}
{'spinning': 20, 'yoga': 9}
20
3 2Mandag har spinning to ganger, og de 14 og 6 legges sammen til 20. Det er
nettopp derfor den siste linja i malen bruker + og ikke =.
De tre hjelpevariablene dag, akt og antall koster tre linjer og sparer
deg for å skrive o[0], o[1] og o[2] fem ganger. Det gjør koden lettere å lese — og å rette.
Merk at len(uke) er 3 (tre dager) mens len(uke["mandag"]) er 2 (to
aktiviteter). De to len-ene teller på hvert sitt nivå.
Slik ville sensor sett på det: de to if-sjekkene er to selvstendige
poeng, og akkumuleringen med + er et tredje. Glemmer du den første sjekken, stopper programmet med KeyError: 'mandag' på aller første runde.
— naturlig pausepunkt —
Hva skriver programmet ut?
d = {}
for par in [["a", "x", 1], ["b", "y", 2], ["a", "y", 3], ["a", "x", 4]]:
ytre = par[0]
indre = par[1]
if ytre not in d:
d[ytre] = {}
if indre not in d[ytre]:
d[ytre][indre] = 0 d[ytre][indre] = d[ytre][indre] + par[2]
print(d)
print(len(d), len(d["a"]))
print(d["a"]["x"])En kollektivrute registrerer passasjerer per dag og per holdeplass, som en liste av[dag, holdeplass, antall].
a) Skriv bygg(data) som returnerer en nøstet ordbok fra dag til
holdeplass til samlet antall.
b) Skriv sum_dag(nostet, dag) som gir det samlede antallet for én dag, eller0 hvis dagen ikke finnes.
c) Test begge med fem registreringer.
Løkke 3 — Løkke og oppslag over to nivåer (~13 min)
Når strukturen er bygget, skal den leses. To ting går igjen: å løpe gjennom begge nivåene, og å slå opp trygt når begge nivåer kan mangle.
Den ytre løkka gir ytternøklene, den indre gir indrenøklene:
uke = {"mandag": {"spinning": 14, "yoga": 9}, "tirsdag": {"spinning": 20}}
for dag in uke:
for akt in uke[dag]:
print(dag, akt, uke[dag][akt])Utskrift:
mandag spinning 14 mandag yoga 9 tirsdag spinning 20Begge løkkevariablene er nøkler, ikke verdier. Verdien hentes med det doble
oppslaget uke[dag][akt].
Den indre løkka går over uke[dag] — den indre ordboka for nettopp den dagen. Skriver du for akt in uke: i den indre løkka, går du gjennom dagene to ganger.
Antall runder til sammen er summen av størrelsene på de indre ordbøkene — her
2 pluss 1, altså 3.
Begge nivåer kan mangle, og hver av dem stopper programmet:
uke = {"mandag": {"spinning": 14}}
print(uke["tirsdag"]["spinning"])
print(uke["mandag"]["yoga"])Første linje gir KeyError: 'tirsdag', andre gir KeyError: 'yoga'. Blokken er merket som ikke-kjørbar fordi feilene er plantet med vilje.
Den trygge formen sjekker begge, hver for seg:
def hent(uke, dag, akt):
if dag not in uke:
return 0 if akt not in uke[dag]:
return 0 return uke[dag][akt]
uke = {"mandag": {"spinning": 14}}
print(hent(uke, "mandag", "spinning"))
print(hent(uke, "mandag", "yoga"))
print(hent(uke, "tirsdag", "spinning"))Utskrift:
14
0
0Rekkefølgen på de to sjekkene er ikke valgfri. Sjekker du den indre først —if akt not in uke[dag]: — stopper programmet allerede der når dagen mangler, fordi uke[dag] slås opp før not in rekker å gjøre noe.
Samme feil ved oppbygging. d[ytre][indre] = 0 uten at d[ytre] = {} er
gjort først, stopper på ytternøkkelen. Det er den vanligste formen feilen tar i
Oppgave 5.
En nøstet ordbok går fra dag til aktivitet til deltakertall. Skriv funksjoner som finner totalt antall deltakere, den travleste dagen, og alle aktiviteter som brukes på minst to dager.
Tre funksjoner, tre mønstre — alle med to nivåers løkke:
def totalt(uke):
total = 0 for dag in uke:
for akt in uke[dag]:
total = total + uke[dag][akt]
return total
def travleste_dag(uke):
beste = None beste_antall = 0 for dag in uke:
sum_dag = 0 for akt in uke[dag]:
sum_dag = sum_dag + uke[dag][akt]
if sum_dag > beste_antall:
beste = dag beste_antall = sum_dag return beste
def brukt_flere_dager(uke, grense):
teller = {}
for dag in uke:
for akt in uke[dag]:
if akt not in teller:
teller[akt] = 0 teller[akt] = teller[akt] + 1 svar = []
for akt in teller:
if teller[akt] >= grense:
svar.append(akt)
return svar
uke = {"mandag": {"spinning": 14, "yoga": 9},
"tirsdag": {"spinning": 20},
"onsdag": {"yoga": 3, "styrke": 11}}
print(totalt(uke))
print(travleste_dag(uke))
print(brukt_flere_dager(uke, 2))Utskrift:
57 mandag
['spinning', 'yoga']Legg merke til hvor akkumulatorene står i de tre funksjonene.
I totalt står total = 0 utenfor begge løkkene — den skal summere alt.
I travleste_dag står sum_dag = 0 inne i den ytre løkka, fordi den skal nullstilles for hver dag. Det er nettopp den plasseringen oppgaven tester: flytter du den ut, summerer du alle dagene sammen i stedet for å sammenligne dem.
I brukt_flere_dager bygges et regnskap i en to nivåers løkke, og det leses i en enkel løkke etterpå. Samme todeling som i
kap. 6.3.
Mandag har 14 pluss 9, altså 23, mot tirsdags 20 og onsdags 14. Både spinning
og yoga brukes på to dager; styrke bare på én.
Slik ville sensor sett på det: i sjanger G er den todelte løkkestrukturen
selve poenget, og riktig struktur belønnes selv med en indeksfeil. Plasseringen av akkumulatoren — inne i eller utenfor den ytre løkka — er et selvstendig poeng i seg selv.
Hva skriver programmet ut?
uke = {"mandag": {"a": 3, "b": 5},
"tirsdag": {"a": 7},
"onsdag": {"b": 2, "c": 4}}
antall_runder = 0 total = 0 for dag in uke:
for akt in uke[dag]:
antall_runder = antall_runder + 1 total = total + uke[dag][akt]
print(antall_runder, total)
print(len(uke), len(uke["mandag"]), len(uke["tirsdag"]))En nøstet ordbok går fra ukedag til rett til antall solgte porsjoner i en kantine.
a) Skriv solgt(d, dag, rett) som gir antallet, eller 0 hvis dagen eller
retten ikke finnes.
b) Skriv totalt_per_rett(d) som gir en flat ordbok fra rett til samlet
antall over alle dagene.
c) Test begge.
Løkke 4 — Nøstet akkumulering som sporingsfelle (~12 min)
Nøstede løkker dukker også opp i Oppgave 1, kodesporingen — og der er de en av de vanligste fellene.
Spørsmålet er alltid det samme: hvor mange runder går den indre løkka til sammen, og hva står akkumulatoren på til slutt?
Med faste grenser ganges antallet:
antall = 0 for i in range(3):
for j in range(4):
antall = antall + 1 print(antall)Utskrift:
12Tre ytre runder ganger fire indre.
Med varierende grenser må du legge sammen:
antall = 0 for i in range(4):
for j in range(i):
antall = antall + 1 print(antall)Utskrift:
6Den indre løkka går 0, 1, 2 og 3 ganger — til sammen 6. range(0) gir ingen runder i det hele tatt, og det er den delen folk glemmer.
Skriv opp én linje per ytre runde når grensene varierer. Det tar ti sekunder
og fjerner hele fellen.
Tre plasseringer, tre helt ulike svar:
tall = [[1, 2], [3, 4]]
utenfor = 0 for rad in tall:
for x in rad:
utenfor = utenfor + x print("utenfor:", utenfor)
for rad in tall:
mellom = 0 for x in rad:
mellom = mellom + x print("mellom: ", mellom)
for rad in tall:
for x in rad:
innerst = 0 innerst = innerst + x print("innerst:", innerst)Utskrift:
utenfor: 10 mellom: 7 innerst: 4Utenfor begge løkkene: summen av alt.
Mellom løkkene: nullstilles for hver indre liste, så til slutt står den på
summen av den siste — her 3 pluss 4.
Innerst: nullstilles hver eneste runde, så den står på det siste
elementet.
Å se hvilken av de tre plasseringene koden har, er ofte hele sporingsoppgaven.
Hva skriver programmet ut? Vis sporingen linje for linje.
Snutten under er skrevet i samme form som en Oppgave 1-deloppgave:
rader = [[2, 5], [1, 3, 4], [7]]
total = 0 rad_sum = 0 antall = 0 for rad in rader:
rad_sum = 0 for x in rad:
total = total + x rad_sum = rad_sum + x antall = antall + 1 print("rad ferdig:", rad_sum)
print(total, rad_sum, antall)Utskrift:
rad ferdig: 7 rad ferdig: 8 rad ferdig: 7
22 7 6Sporingstavle, én rad per indre liste:
| Indre liste | Runder | total etter | rad_sum etter | antall etter |
|---|---|---|---|---|
[2, 5] | 2 | 7 | 7 | 2 |
[1, 3, 4] | 3 | 15 | 8 | 5 |
[7] | 1 | 22 | 7 | 6 |
Tre akkumulatorer med tre ulike plasseringer.
total og antall står utenfor begge løkkene og samler opp alt.rad_sum nullstilles inne i den ytre løkka, så den viser summen av én rad om gangen. Til slutt står den på den siste raden, altså 7.print("rad ferdig:", rad_sum) står i den ytre løkka, ikke i den indre — se på innrykket. Derfor kommer den tre ganger, ikke seks.Antall runder er 2 pluss 3 pluss 1, altså 6 — ikke 3 ganger noe, siden radene
har ulik lengde.
På eksamen skrives alle fire linjene, i riktig rekkefølge, og tallene på siste
linje med ett mellomrom mellom.
Hva skriver programmet ut?
total = 0 for i in range(4):
for j in range(i):
total = total + j print(total)
antall = 0 for i in range(3):
for j in range(3):
if i == j:
antall = antall + 1 print(antall)En nøstet liste holder poeng per runde for hver spiller: [[3, 5, 2], [7, 1], [4, 4, 4, 4]], der hver indre liste er én spiller.
a) Skriv sum_per_spiller(data) som returnerer en liste med summen for
hver spiller.
b) Skriv beste_spiller(data) som returnerer indeksen til spilleren med
høyest sum.
c) Skriv alle_over(data, grense) som returnerer True bare hvis alle
spillerne har en sum over grensen.
d) Test alle tre.
En medstudent har skrevet:
def bygg(data):
d = {}
for rad in data:
ytre = rad[0]
indre = rad[1]
if indre not in d[ytre]:
d[ytre] = {}
d[ytre][indre] = 0 d[ytre][indre] = rad[2]
return da) Funksjonen har tre feil. Hvilke?
b) Gi et konkret moteksempel på den som stopper programmet.
c) Skriv den rettede funksjonen.
Fem feil koster nesten alle poengene som mistes på nøstede strukturer:
- #14 i nøstet form — bare én sjekk. Både ytternøkkelen og indrenøkkelen kan
mangle, og hver av dem stopper programmet. To sjekker, i riktig rekkefølge:
ytre først.
- Akkumulatoren på feil nivå. Utenfor begge løkkene summerer alt; inne i den
ytre nullstilles den per indre liste; innerst nullstilles den hver runde. Tre helt ulike svar.
- Å blande de to nivåene. y[i][j] og y[j][i] er ulike oppslag, og
for akt in uke: i den indre løkka går gjennom dagene på nytt.
- Å telle runder feil. Med faste grenser er antallet et produkt; med
varierende grenser en sum. Og range(0) gir null runder.
- #7 — for tidlig retur i en «alle»-sjekk. return False inne i løkka,
return True etter. Å snu dem gir feil svar.
Og én lesefelle: len teller alltid ett nivå. len(y) er antall indre lister, ikke antall tall.
Begrepsbank
Begrepsbanken er flashcard- og repetisjonsstoff — den gjentar det du nettopp har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder kjernestoffet.
En liste der elementene selv er lister: [[3, 8], [1, 4, 9], [7]].
len på ytterlista teller de indre listene — her 3, ikke 6.
De indre listene trenger ikke være like lange, og det er nettopp derfor antall runder i en to nivåers løkke må legges sammen og ikke ganges.
En ordbok der verdiene selv er ordbøker:{"mandag": {"spinning": 14, "yoga": 9}}.
Ytternøkkelen er den ene inndelingen, indrenøkkelen den andre, og verdien er tallet.
De indre ordbøkene trenger ikke ha de samme nøklene. Det er hovedgrunnen til at et dobbelt oppslag må sjekke begge nivåene.
y[i][j] for lister, d[ytre][indre] for ordbøker.Les fra venstre: den første hakeparentesen velger den indre strukturen, den andre velger et element i den.
Rekkefølgen er hele fellen. y[0][2] og y[2][0] er to helt ulike oppslag,
og det ene kan stoppe programmet mens det andre virker.
En løkke inne i en løkke.
For lister: for indre in y: og for x in indre: — den ytre variabelen er en
liste.
For ordbøker: for ytre in d: og for indre in d[ytre]: — begge variablene er nøkler, og verdien hentes med d[ytre][indre].
Skriver du for indre in d: i den indre løkka, går du gjennom ytternøklene to ganger.
To sjekker, ikke én:
if ytre not in d:
d[ytre] = {}
if indre not in d[ytre]:
d[ytre][indre] = 0 d[ytre][indre] = d[ytre][indre] + vBlokken er en mal og er merket som ikke-kjørbar.
Først den indre ordboka, så den indre nøkkelen, så akkumuleringen. Hopper du over den første, stopper programmet på ytternøkkelen — feilkode #14.
Ytternøkkelen sjekkes først, alltid.
if indre not in d[ytre]: slår opp d[ytre] før not in rekker å virke. På en ytternøkkel som ikke finnes, stopper programmet der.
Samme regel gjelder i en trygg oppslagsfunksjon: if dag not in d: return 0 først, if akt not in d[dag]: return 0 etterpå.
Inne i den ytre løkka: nullstilles for hver indre liste, og gir «per
rad»-svar.
Innerst i den indre løkka: nullstilles hver runde, og står til slutt på det
siste elementet.
Å se hvilken av de tre plasseringene koden har, er ofte hele sporingsoppgaven — og å velge riktig plassering er et selvstendig poeng i sjanger
G.
Med faste grenser ganges antallet: range(3) inne i range(4) gir 12 runder.
Med varierende grenser legges de sammen: range(i) inne i range(4) gir
0 pluss 1 pluss 2 pluss 3, altså 6.
range(0) gir null runder. Det er den delen folk glemmer, og den er plantet med vilje i sporingsoppgavene.
len(y) teller elementene i ytterstrukturen; len(y[0]) teller elementene i den første indre.Det totale antallet finnes i ingen av dem. Skal du telle alt, må du gå gjennom begge nivåene med en teller.
For en nøstet ordbok er det det samme: len(d) er antall ytternøkler,len(d["a"]) er antall indrenøkler under a.
Formen for å hente en verdi når begge nivåer kan mangle:
def hent(d, ytre, indre):
if ytre not in d:
return 0 if indre not in d[ytre]:
return 0 return d[ytre][indre]Blokken er en mal og er merket som ikke-kjørbar.
Tidlig retur er riktig her, i motsetning til i en finn-beste-løkke: funksjonen
har ingenting mer å gjøre når den vet at nøkkelen mangler.
Hva den skal returnere ved «ikke funnet», sier oppgaveteksten. 0 er naturlig når svaret skal regnes med; None når det skal sammenlignes.
Å summere bort det ene nivået: fra dag → rett → antall til rett → totalt antall.
Formen er teller-idiomet med en to nivåers løkke rundt seg, og resultatet er en
vanlig ordbok.
Kjenn den igjen i oppgaveteksten på «gi en ordbok fra … til totalt antall …»
eller «samlet for alle dagene».
En helt vanlig og lovlig situasjon: [[1, 2], [3], [4, 5, 6]], eller en dag som mangler en aktivitet.
Løkkene bryr seg ikke — for x in indre: går så mange runder som den strukturen er lang.
Men antall runder må da legges sammen, ikke ganges, og et dobbelt oppslag må sjekke begge nivåene. Begge deler er plantet i eksamensoppgavene.
Samme idé, to ulike inngangsnøkler.
Lista har rekkefølge og indekseres med tall. Bruk den når posisjonen betyr
noe — «rad 0 er spiller 1».
Ordboka slås opp med navn og har ingen posisjon utover
innsettingsrekkefølgen. Bruk den når inndelingene har navn — «mandag», «spinning».
Oppgaveteksten sier som regel hvilken: «en liste av lister» eller «en ordbok fra
… til en ordbok fra … til …».
for i in range(len(liste)): når det er indeksen du trenger, ikke bare verdien.Typisk når svaret skal være «hvilken spiller», og spillerne er nummerert etter plassen i lista.
Verdien hentes da med liste[i]. Trenger du bare verdien, er for x in liste: enklere og mindre å bomme på.
return False inne i løkka, return True etter den.Å snu de to gjør at funksjonen svarer ja så snart ett element passer — feilkode #7, for tidlig retur.
Linjen etter løkka er obligatorisk. Glemmer du den, gir funksjonen None, ogNone oppfører seg som usant i en if — så feilen er stum.
dag = rad[0], akt = rad[1], antall = rad[2] øverst i kroppen, i stedet for å skrive rad[0] fem ganger.Tre linjer ekstra gjør resten mye lettere å lese — og å rette. I en nøstet struktur, der du allerede har to nivåer å holde styr på, er det verdt hvert tegn.
Det gir ingen ekstra poeng i seg selv, men det reduserer sjansen for å blande indeksene betraktelig.
To funksjoner over nøstede lister eller ordbøker, 4–5 poeng hver, til sammen
8–10 poeng.
Den andre bygger ofte på den første: «bruk funksjonen fra a) til å …». Da kan du kalle den selv om du ikke fikk den helt riktig — sensor vet hva den skulle gjøre.
Sjangeren står i 4 av 6 moderne sett (67 %), og den er den siste oppgaven i settet.
Begge nivåer husker den rekkefølgen nøklene ble opprettet i.
Bygger du ordboka ovenfra og ned fra en liste, får du nøklene i den rekkefølgen dataene kom.
Det er verdt å vite når du skal spore en utskrift av hele strukturen — Python skriver den ut med krøllparenteser, enkle anførselstegn rundt tekstnøkler, kolon mellom nøkkel og verdi, og komma mellom parene.
Å slå opp eller legge til på en nøkkel som ikke er opprettet — nå på to nivåer.
d[ytre][indre] = 0 uten at d[ytre] = {} er gjort først, stopper med KeyError på ytternøkkelen. Det er den vanligste feilen i hele kapitlet.
Motgiften er mekanisk: skriv to if-sjekker hver gang du bygger en nøstet struktur, i rekkefølgen ytre, indre.
Fordi virkeligheten ofte har to inndelinger samtidig: dag og aktivitet, uke
og dag, spiller og runde.
Alternativet — én ordbok med sammensatte nøkler som "mandag-spinning" — virker, men gjør det umulig å spørre «hva skjedde på mandag?» uten å plukke tekster fra hverandre.
Den nøstede strukturen holder de to inndelingene atskilt, og det er nettopp det som gjør «summer per dag» og «summer per aktivitet» til to enkle løkker.
Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.
Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Universitetet i Oslo. Dette er ikke offisielt studiemateriell. Les mer.