Kombinere dictionaries med dictionaries og lister

Akkurat som vi kan ha lister inni lister, kan vi ha dictionaries inni dictionaries. Eksempel 1 har en dictionary som heter agentbil, der verdiene til nøklene "motordata" og "dekkdata" er egne dictionaries.

Eksempel 1:

agentbil = {
    "eier": "James Bond",
    "merke": "Aston Martin",
    "motordata": {"effekt": 125, "slagvolum": 2.1, "dreiemoment": 225},
    "dekkdata": {"bredde": 155, "profil": 70, "felg": 12}
}

I Python Tutor ser det slik ut:

Illustrasjon av dictionary i dictionary

For å referere til en nøkkel i en dictionary inni en dictionary må vi bruke 2 indekser, én for hver dictionary. For eksempel agentbil["dekkdata"]["bredde"] for å finne dekkbredden til agentbil i eksempel 1.

Vi kan også ha dictionaries i lister. Eksempel 2 har ei liste som inneholder dictionaries som kopler postnummer og sted.

Eksempel 2:

postinfo = [
    {"nummer": 4225, "navn": "Lyngdal"},
    {"nummer": 4586, "navn": "Korshamn"},
    {"nummer": 4590, "navn": "Snartemo"},
    {"nummer": 4596, "navn": "Eiken"}
]

I Python Tutor ser det slik ut:

Illustrasjon av dictionary i liste

For å referere til en nøkkel i en dictionary inni ei liste, må vi bruke 2 indekser, én for lista og én for dictionary. For eksempel vil postinfo[1]["navn"] i eksempel 2 være "Korshamn" fordi element nummer 1 i postinfo inneholder en dictionary med nøkkel-verdi-paret "navn": "Korshamn".

Koden under vil gjennomløpe lista i eksempel 2 og skrive ut informasjon om postnummer og navn.

for sted in postinfo:
    print(f"{sted['navn']} har postnummer {sted['nummer']}.")

Vi kan også lister i dictionaries. Eksempel 3 inneholder en dictionary med forfattere som nøkler og lister med boktitler som verdier.

Eksempel 3:

katalog = {
    "Knut Hamsun": ["Sult", "Markens grøde", "Victoria"],
    "Ernest Hemingway": ["Og solen går sin gang", "Den gamle mannen og havet"],
    "Roald Dahl": ["Charlie og sjokoladefabrikken", "Heksene", "Matilda", "SVK"]
}

I Python Tutor ser det slik ut:

Illustrasjon av lister i dictionary

For å referere til et element i ei liste inni en dictionary, må vi bruke 2 indekser, én for dictionary og én for lista. For eksempel vil katalog["Roald Dahl"][1] i eksempel 3 være "Heksene" fordi element nummer 1 i lista knyttet til nøkkel "Roald Dahl", inneholder "Heksene".

Koden under vil gjennomløpe lista i eksempel 3 og skrive ut informasjon om forfattere og bøker.

for forfatter, titler in katalog.items():
    print(f"{forfatter} har skrevet:", end = " ")
    for tittel in titler:
        print(f"'{tittel}'", end = " ")
    print()

Det er ingen teoretisk grense for hvor mange dictionaries og lister vi kan nøste inni hverandre, men i praksis blir det sjelden bruk for mer enn 2-3 nivåer.

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Lister som inneholder lister

Ei liste kan inneholde elementer av alle datatyper. Vi har sett eksempler på lister med heltall, flyttall, strenger og boolske variabler. Men ei liste kan også inneholde andre lister.

Eksempel 1:

Vi har målt maksimumstemperaturen i en by hver dag i tre uker, og har laget følgende oversikt

  Dag 1 Dag 2 Dag 3 Dag 4 Dag 5 Dag 6 Dag 7
Uke 1 12 10 14 7 8 11 10
Uke 2 10 7 9 6 6 8 15
Uke 3 10 5 3 6 4 3 2

Her kan vi representere hver uke som ei liste med 7 elementer i Pyton:

grader_uke_1 = [12, 10, 14, 7, 8, 11, 10]
grader_uke_2 = [10, 7, 9, 6, 6, 8, 15]
grader_uke_3 = [10, 5, 3, 6, 4, 3, 2]

Disse listene kan vi så sette inn i ei ny liste:

grader = [grader_uke_1, grader_uke_2, grader_uke_3]

I Python Tutor ser det slik ut:

Illustrasjon av lister i lister

Vi ser at grader_uke_1, grader_uke_2 og grader_uke_3 refererer til hver si liste, mens grader referer til ei liste som igjen refererer til grader_uke_1, grader_uke_2 og grader_uke_3.

Vi kan for så vidt også opprette grader uten å gå veien om ukelistene:

grader = [[12, 10, 14, 7, 8, 11, 10], [10, 7, 9, 6, 6, 8, 15], [10, 5, 3, 6, 4, 3, 2]]

I eksempel 1 har vi ei liste som inneholder 3 elementer som hver er lister med 7 elementer. For å referere til et enkeltelement må vi da bruke to indekser. Én for å velge ei av listene, og én for å velge et element i denne lista igjen. Indeksene starter på 0, så hvis vi har opprettet grader slik som i eksempel 1, og skriver

print(grader[0][2])

får vi skrevet ut 14 fordi element nummer 0 i grader er lista grader_uke_1, og element nummer 2 i grader_uke_1 er 14.

Generelt vil indeksene [m][n] gi et element med indeks n i lista med indeks m.

Oppgave 1:

Basert på lista grader fra eksempel 1, avgjør hva som blir skrevet ut hvis vi kjører følgende kode:

print(grader[1][2])
print(grader[2][1])
print(grader[0])

Gjør oppgaven på papir først, og sjekk så ved å kjøre koden om du har rett.

Se løsningsforslag

Vil vi gjennomløpe alle elementene i ei liste med lister, må vi ha to nøstede løkker.

Eksempel 2:

Vi har opprettet lista grader som i eksempel 1, og skal finne den høyeste temperaturen i løpet av de tre ukene. Det kan vi gjøre ved hjelp av følgende Python-kode:

# Finner høyeste tall i liste med lister
maks_grader = grader[0][0]  # Startverdi lik dag 1, uke 1
for grader_uke in grader:  # Uke for uke
    for grader_dag in grader_uke:  # Dag for dag i uke
        if grader_dag > maks_grader:
            maks_grader = grader_dag
print(f"Høyeste temperatur var {maks_grader} grader.")

I eksempel 2 tar vi utgangspunkt i temperaturen første dag i første uke, og leter så gjennom resten av lista for å se om vi finner noe høyere. Her bruker vi altså to nøstede løkker. Koden

for grader_uke in grader:

vil tilordne liste for liste fra grader til grader_uke, ei liste for hvert gjennomløp i den ytre løkka.

I den indre løkka vil koden

for grader_dag in grader_uke:

tilordne tall for tall i lista grader_uke til grader_dag, ett tall for hvert gjennomløp i den indre løkka.

Legg merke til at grader_uke i den ytre løkka er ei liste, mens grader_dag i den indre løkka er et tall.

Vi kan ikke bruke Python-funksjonen max() til å finne den høyeste temperaturen. max(grader) vil returnere lista for uka med den høyeste summen av temperaturer i stedet for den høyeste enkelttemperaturen.

Det er ikke noen teoretisk grense for hvor mange lister vi kan ha inni hverandre, men i praksis er det sjelden behov for mer enn 2-3.

Lister som ligger inni ei annen liste, trenger ikke være like store.

Eksempel 3:

Koden under oppretter lista diverse, som inneholder 2 lister med henholdsvis 3 og 5 elementer.

diverse = [[1, 2, 3], [1, 2, 3, 4, 5]]

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Den som er vant med å programmere i språk som C, vil kanskje lure på hvorfor vi ikke har pekere i Python. Men ser vi på bildet fra Python Tutor over, skjønner vi at vi har pekere, de er bare implisitte. I eksempel 1 er for eksempel grader en peker til ei liste som inneholder pekere til tre andre lister.

Sortere lister

I artikkelen om liste-metoder blir vi kjent med en del av metodene som er knyttet til lister.

Lister har også en metode for sortering, sort().

Eksempel 1:

Vi oppretter ei liste med tall i vilkårlig rekkefølge, skriver den ut, sorterer den og skriver den ut på nytt.

kaos = [6, -3, 0, 5, 2, 8]
print(kaos)
kaos.sort()
print(kaos)

Vi får først skrevet ut lista slik vi opprettet den, deretter sortert som [−3, 0, 2, 5, 6, 8].

Det er også mulig å få sort() til å sortere i synkende rekkefølge ved å gi inn True som et argument til parameteren reverse.

Eksempel 2:

Vi gjør det samme som i eksempel 1, men angir reverse = True.

kaos = [6, -3, 0, 5, 2, 8]
print(kaos)
kaos.sort(reverse = True)
print(kaos)

Vi får først skrevet ut lista slik vi opprettet den, deretter sortert synkende som [8, 6, 5, 2, 0, −3].

Vi ser at metoden sort() endrer på den opprinnelige lista. Ønsker vi å beholde lista uendret og i stedet få en sortert kopi, kan vi i stedet bruke Python-funksjonen sorted(). Også med sorted() kan vi sortere i synkende rekkefølge ved gi inn True som et argument til parameteren reverse.

Vi skriver følgende kode:

kaos = [6, -3, 0, 5, 2, 8]
print(kaos)
print(sorted(kaos))
print(sorted(kaos, reverse = True))
print(kaos)

Vi får da først skrevet ut den opprinnelige lista, deretter lista sortert stigende og synkende, og i siste utskrift ser vi at den opprinnelige lista er uendret.

Det finnes også en metode som snur rekkefølgen i ei liste, reverse().

Eksempel 4:

Vi skriver følgende kode:

kaos = [6, -3, 0, 5, 2, 8]
print(kaos)
kaos.reverse()
print(kaos)

Vi får først skrevet ut lista slik vi opprettet den, deretter i omvendt rekkefølge som [8, 2, 5, 0, −3, 6].

Oppgave 1:

Skriv Python-kode som oppretter lista kaos som vist i eksemplene, og deretter sorterer lista synkende uten at du angir reverse = True.

Se løsningsforslag

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Kopiere lister

Vi vet at vi kan tilordne verdier fra én variabel til en annen.

Har vi for eksempel variabelen x, som har verdien 3, og skriver

y = x

opprettes det en ny variabel som heter y og får verdien 3.

Endrer vi senere verdien til x, påvirker ikke det verdien y har fått.

Når det gjelder lister, fungerer imidlertid tilordningsmekanismen annerledes. Skriver vi for eksempel

liste_a = [1, 2, 3, 4]
liste_b = liste_a

blir det opprettet en ny variabel som heter liste_b, men selve innholdet i liste_a blir ikke tilordnet liste_b. I stedet blir liste_b en ny variabel som refererer til det samme som liste_a.

Eksempel 1:

Vi kjører følgende Python-kode:

liste_a = [1, 2, 3, 4]
liste_b = liste_a
liste_b[1] = "hei"
print(liste_a)
print(liste_b)

I eksempel 1 oppretter vi først liste_a, så setter vi liste_b lik liste_a, deretter endrer vi et element i liste_b. Når vi så skriver ut både liste_a og liste_b, ser vi at endringen vi gjorde i liste_b også er blitt gjort i liste_a. Grunnen er at liste_a og liste_b egentlig ikke er to forskjellige lister, men bare to forskjellige navn på samme liste.

Bruker vi Python Tutor, ser vi at liste_a og liste_b refererer til samme liste:

Illustrasjon av to lister som er samme objekt

Vil vi kopiere innholdet i ei liste, kan vi enten bruke [:] som indeks for å lage ei del-liste med alle elementene, eller vi kan bruke listemetoden copy().

Eksempel 2:

Vi kjører følgende Python-kode:

liste_a = [1, 2, 3, 4]
liste_b = liste_a[:]
liste_b[1] = "hei"
print(liste_a)
print(liste_b)

og

liste_a = [1, 2, 3, 4]
liste_b = liste_a.copy()
liste_b[1] = "hei"
print(liste_a)
print(liste_b)

I begge tilfeller i eksempel 2 ser vi at endringen vi gjør i liste_b ikke påvirker liste_a. Det er fordi liste_b er blitt ei separat liste med sitt eget innhold.

Bruker vi Python Tutor, ser vi at liste_a og liste_b nå er to forskjellige lister:

Illustrasjon av to lister som er forskjellig objekt

I artikkelen om lokale og globale variabler lærer vi at variabler i funksjoner er lokale, med følgende eksempel:

Vi har en funksjon, kvadrer(), som kvadrerer verdien til parameteren x:

def kvadrer(x):
    x = x**2

I hovedprogrammet oppretter vi så en variabel, x, med verdien 4, kaller opp funksjonen med x som argument, og skriver ut verdien til x etterpå:

x = 4
kvadrer(x)
print(x)

Vi ser da at x utenfor funksjonen ikke endrer seg.

Når vi kaller opp en funksjon med ei liste som argument, er det imidlertid bare en referanse til lista som overføres til funksjonsparameteren.

Eksempel 3:

Vi har funksjonen kvadrer, som opphøyer alle elementer i ei liste i andre:

def kvadrer(liste):
    for indeks in range(len(liste)):
        liste[indeks] **= 2

I hovedprogrammet oppretter vi så lista siffer med elementene 1, 2, 3, kaller opp kvadrer() med siffer som argument, og skriver ut innholdet etterpå:

siffer = [1, 2, 3]
kvadrer(siffer)
print(siffer)

Vi ser at innholdet i siffer er blitt kvadrert, enda vi ikke har koplet siffer til noen returverdi fra funksjonen.

Bruker vi Python Tutor, ser vi at siffer i hovedprogrammet og liste i kvadrer() refererer til samme liste:

Illustrasjon av hovedprogram og funksjon som refererer til lister som er samme objekt

Oppgave 1:

I eksempel 3 kalte vi opp funksjonen kvadrer() med siffer som argument på denne måten:

kvadrer(siffer)

Vi så da et endringene som kvadrer() gjorde på sin parameter, også hadde effekt på siffer. Hvordan kan vi skrive om oppkallet av funksjonen slik at siffer ikke endres?

Se løsningsforslag

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Deler av lister

Det er mulig til å referere til deler av ei liste ved å skrive inn to indekser med kolon mellom, der [a:b] gir ei liste som består av elementene med indeks fra og med a inntil b.

Eksempel 1:

Vi oppretter ei liste som heter primtall:

primtall = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Skriver vi så for eksempel

print(primtall[1:4])

får vi skrevet ut ei del-liste som består av elementene med indeks 1, 2 og 3 i primtall, det vil si [3, 5, 7].

Det er viktig å merke seg at indekser på formen [a:b] gir ei ny liste, ikke enkeltelementer.

Utelater vi a, betyr det at vi skal starte på første element i lista, utelater vi b, betyr det at vi skal slutte på siste element i lista.

Eksempel 2:

Vi oppretter ei liste med 10 elementer som heter primtall:

primtall = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Skriver vi så for eksempel

print(primtall[3:4])

får vi skrevet ut ei del-liste som består av elementet med indeks 3 i primtall, det vil si [7].

Skriver vi

print(primtall[:4])

får vi skrevet ut ei del-liste som består av elementene med indekser 0, 1, 2 og 3 i primtall, det vil si [2, 3, 5, 7].

Skriver vi

print(primtall[4:])

får vi skrevet ut ei del-liste som består av elementene med indekser 4, 5, 6, 7, 8 og 9 i primtall, det vil si [11, 13, 17, 19, 23, 29].

Skriver vi

print(primtall[:])

får vi skrevet ut ei del-liste som består av alle elementene i primtall, det vil si [2, 3, 5, 7, 11, 13, 17, 19, 23, 29].

På samme måte som i range(), kan vi angi en skrittverdi når vi genererer del-lister. [a:b:c] gir ei liste som består av elementene med indeks fra og med a inntil b i skritt på c.

Eksempel 3:

Vi oppretter ei liste som heter primtall, som i eksempel 2.

primtall = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Skriver vi så for eksempel

print(primtall[1:9:2])

får vi skrevet ut ei del-liste som består av elementene med indekser 1, 3, 5 og 7 i primtall, det vil si [3, 7, 13, 19].

Skriver vi

print(primtall[-1:-5:-1])

får vi skrevet ut ei del-liste som består av elementene med indekser −1, −2, −3 og −4 i primtall, det vil si [29, 23, 19, 17].

Skriver vi

print(primtall[::2])

får vi skrevet ut ei del-liste som består av elementene med indekser 0, 2, 4, 6 og 8 i primtall, det vil si [2, 5, 11, 17, 23].

Oppgave 1:

Vi oppretter ei liste som heter kvadrat:

kvadrat = [1, 4, 9, 16, 25, 36]

Hva refererer da kvadrat[1:3], kvadrat[:3], kvadrat[2:] og kvadrat[:5:2] til? Skriv først opp svarene dine, og bruk så print() i Python til å sjekke om du har rett.

Se løsningsforslag

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Negative indekser i lister

I artikkelen om lister ser vi at lister er variabler som kan inneholde flere elementer, og at vi kan referere til enkeltelementer i ei liste ved hjelp av indekser, der første element i ei liste har indeks 0. Indeksene i ei liste med n elementer vil altså være tallene fra og med 0 til og med n−1. Bruker vi en indeks som er n eller større, får vi feilmeldingen "IndexError: list index out of range".

Antall elementer i ei liste kan vi finne ved hjelp av Python-funksjonen len().

Eksempel 1:

Vi oppretter ei liste som heter primtall, og inneholder de 10 første primtallene:

primtall = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

len(primtall) vil returnere 10.

Indeksene i primtall går da fra og med 0 til og med 9.

Skriver vi så for eksempel

print(primtall[0], primtall[9])

får vi skrevet ut 2 og 29.

Skriver vi

print(primtall[10])

får vi en feilmelding.

Vi kan imidlertid også bruke negative tall som indekser. Negative indekser regner fra høyre mot venstre. Siste element i ei liste har indeks −1, nest siste −2, og så videre. Første element i ei liste med n elementer vil ha indeks −n. Bruker vi en indeks som er mindre enn −n, får vi samme feilmelding som hvis vi bruker en indeks som er n eller større, "IndexError: list index out of range".

Positive indekser i ei liste med n elementer går altså fra 0 til n−1, fra venstre mot høyre, mens negative indekser går fra −1 til −n fra høyre mot venstre.

Eksempel 2:

Vi oppretter ei liste som heter primtall, som i eksempel 1:

primtall = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Skriver vi så for eksempel

print(primtall[-1], primtall[-10])

får vi skrevet ut 29 og 2.

Oppgave 1:

Vi oppretter ei liste som heter kvadrat:

kvadrat = [1, 4, 9, 16, 25, 36]

Hvilke tall refererer da kvadrat[-2] og kvadrat[-6] til? Skriv først opp svarene dine, og bruk så print() i Python til å sjekke om du har rett.

Se løsningsforslag

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Oppprette lister med inline-«for»

Av og til kan det være at vi skal opprette lister som inneholder følger med tall som ikke er hele. Da kan vi ikke bruke range() direkte, fordi range() bare gir ut heltall. Det vi kan gjøre, derimot, er å bruke range() til å generer heltall, og så beregne tallene vi ønsker, ut fra disse. La oss for eksempel si at vi skal opprette ei liste, x, som inneholder tallene 0,1, 0,2, 0,3 og 0,4. Da kan vi la range() generere heltallene fra 1 til 4, og så dividere disse med 10 før vi legger dem inn i x, slik det er vist i eksempel 1.

Eksempel 1:

# Oppretter lista x med tallene 0,1, 0,2, 0,3 og 0,4
x = []
for n in range(1, 5):
    x.append(n/10)

I eksempel 1 oppretter vi først x som ei tom liste, og går så inn i ei løkke der variabelen n gjennomløper heltallene fra 1 til 4, mens vi legger n/10 til på slutten av lista.

Ved hjelp av noe som heter inline-for, kan vi imidlertid erstatte løkka med kode på én enkelt linje, slik det er vist i eksempel 2.

Eksempel 2:

# Oppretter lista x med tallene 0,1, 0,2, 0,3, 0,4
x = [n/10 for n in range(1, 5)]

I eksempel 2 ser vi at vi mellom klammeparentesene bruker samme uttrykk som i første linje i for-løkka i eksempel 1, for n in range(1, 5). I stedet for å bruke en innrykket blokk til å angi hva vi skal gjøre med løkkevariabelen n, skriver vi imidlertid bare et uttrykk som bruker n, foran kodeordet for, slik som n/10 i eksempel 2.

Denne mekanismen heter list comprehension på engelsk, og kalles derfor også listekomprehensjon på norsk.

Oppgave 1:

Vi har koden under, som oppretter ei liste, y, med kvadratet av heltallene fra 1 til 10. 

# Oppretter lista y med tallene 1, 4, 9, ...
y = []
for n in list(range(1, 11))
    y.append(n**2)

Skriv om koden slik at den bruker inline-for til å opprette y.

Se løsningsforslag

Inline-for er et eksempel på inline-kode, som det finnes mange varianter av

Inline-for kan også brukes hvis vi skal opprette ei liste med innhold beregnet ut fra innholdet i en annen liste, slik det er vist i eksempel 3. Der oppretter vi først lista x som i eksempel 2, men oppretter også lista y med tallene fra x opphøyd i tredje.

Eksempel 3:

# Oppretter lista x med tallene 0,1, 0,2, 0,3, 0,4,
# og lista y med n**3 for hver n i x
x = [n/10 for n in range(1, 5)]
y = [n**3 for n in x]

Oppgave 2:

Vi har koden under, som oppretter ei liste, x, med heltallene fra 1 til 10, og ei liste, z, med 5n2 + 3n − 4 for hver n i x.

# Oppretter lista x med tallene 1 ... 10,
# og lista z med 5n**2 + 3n - 4 for hver n i x
x = list(range(1, 11))
z = []
for n in x:
    z.append(5 * n**2 + 3 * n - 4)

Skriv om koden slik at den bruker inline-for til å opprette z.

Se løsningsforslag

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Søke i lister

Å søke etter innhold i lister er noe vil ha behov for å gjøre mye. For å avgjøre om en verdi finnes i ei liste eller ikke, kan vi bruke kodeordet in. Hvis liste er ei liste og a en verdi, vil uttrykket a in liste være True hvis a finnes i liste, False hvis ikke.

Eksempel 1:

# Oppretter lista demo, og lar brukeren søke etter tall
demo = [7, -3, 8, 4, 8]
tall = int(input("Hvilket tall vil du søke etter? "))
print(tall in demo)

Skriver vi for eksempel at vi vil søke etter 7, får vi skrevet ut True. Skriver vi at vi vil søke etter 11, får vi skrevet ut False.

I stedet for å skrive ut True og False direkte kan vi bruke verdien i en if-konstruksjon, som i eksempel 2.

Eksempel 2:

# Oppretter lista demo, og lar brukeren søke etter tall
demo = [7, -3, 8, 4, 8]
tall = int(input("Hvilket tall vil du søke etter? "))
if tall in demo:
    print(f"{tall} finnes i demo.")
else:
    print(f"{tall} finnes ikke i demo.")

Skriver vi for eksempel at vi vil søke etter 7, får vi skrevet ut 7 finnes i demo. Skriver vi at vi vil søke etter 11, får vi skrevet ut 11 finnes ikke i demo.

Er vi interessert i indeksen til verdien vi søker etter, kan vi bruke liste-metoden index(), som beskrives i artikkelen om liste-metoder. index() finner indeksen til første forekomst av et element i ei liste. Dersom elementet ikke finnes i lista, får vi imidlertid en feilmelding. Før vi bruker index(), bruker vi derfor in til å sjekke om elementet faktisk finnes i lista, slik det er vist i eksempel 3.

Eksempel 3:

# Oppretter lista demo, og lar brukeren finne indeks til et tall
demo = [7, -3, 8, 4, 8]
tall = int(input("Hvilket tall vil du finne indeks til? "))
if tall in demo:
    print(f"{tall} har indeks {demo.index(tall)}.")
else:
    print(f"{tall} finnes ikke i lista.")

Skriver vi for eksempel at vi vil finne indeks til 7, får vi skrevet ut 7 har indeks 0. Skriver vi at vi vil finne indeks til 11, får vi skrevet ut 11 finnes ikke i lista.

Ofte har vi imidlertid behov for å gjøre mer avanserte søk i ei liste, der vi selv må skrive kode som gjennomløper lista og sjekker elementene ett for ett.

I eksempel 4 undersøker vi hvor mange tall i ei liste som er partall. Et tall, a, er partall hvis a % 2 == 0.

Eksempel 4:

# Oppretter lista demo, og teller antall partall i lista
demo = [7, -3, 8, 4, 8]
antall = 0
for tall in demo:
    if tall % 2 == 0:  # Tallet er et partall
        antall += 1
print(f"Lista inneholder {antall} partall.")

For å telle partall oppretter vi en variabel å telle med. Vi har kalt den antall, men den kan hete hva som helst. Variabelen setter vi i utgangspunktet til 0, og øker verdien med 1 for hvert partall vi finner. En slik variabel kaller vi gjerne en akkumulator.

Når vi kjører koden, får vi skrevet ut Lista inneholder 3 partall., fordi den inneholder partallene 8, 4 og 8.

Oppgave 1:

Skriv kode som oppretter lista ensifrede, som inneholder heltallene fra og med 1 til og med 9, og skriver ut hvor mange av tallene i lista som er delelige med 4.

Riktig svar er 2, nemlig tallene 4 og 8.

Hint: Husk at du kan bruke list(range()) til å generere ei liste med tall.

Hint: Et tall, a, er delelig med 4 hvis a % 4 == 0.

Se løsningsforslag

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Gjenomløpe lister

Gjennomløpe med forin

I artikkelen om for-løkker ser vi hvordan vi kan bruke range() til å tildele verdier til en løkkevariabel. Nå skal vi se at vi også kan bruke ei liste til det samme. Elementene i lista blir da én for én tildelt til løkkevariabelen når løkka gjennomløpes.

Eksempel 1 viser hvordan vi kan bruke ei liste i ei for-løkke til å skrive ut innholdet i lista demo, element for element.

Eksempel 1:

# Oppretter lista demo og skriver ut innholdet, element for element
demo = [7, -3, 8, 4, 8]
for n in demo:
    print(n)

Oppgave 1:

Skriv Python-kode som oppretter ei liste som inneholder alle oddetall fra og med 1 til og med 19, og skriver dem ut, ett for ett.

Av og til kan det være at vi ønsker å få nummerert elementene vi henter ut fra ei liste. Til det kan vi bruke funksjonen enumerate(). enumerate() returnerer et tallpar, der et løpenummer kommer først, deretter selve elementet.

La oss for eksempel si at vi har ei liste med primtallene under 30, og ønsker å skrive dem ut på formen Primtall nummer 1 er 2, Primtall nummer 2 er 3, og så videre. Det kan vi gjøre som vist i eksempel 2.

Se løsningsforslag

Eksempel 2:

# Oppretter ei liste med primtall og skriver dem ut nummerert
primliste = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
for nummer, primtall in enumerate(primliste):
    print(f"Primtall nummer {nummer + 1} er {primtall}")

Grunnen til at vi skriver nummer + 1 i stedet for bare nummer, er at løpenumrene starter på 0, på samme måte som indekser. Det er imidlertid mulig å angi en startverdi for løpenummeret ved å angi teksten «start» sammen med tallet vi vil starte på. Eksempel 3 gjør det samme som eksempel 2, men angir at løpenummeret skal starte på 1, slik at vi slipper å addere 1 til nummer i utskriften.

Eksempel 3:

# Oppretter ei liste med primtall og skriver dem ut nummerert
primliste = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
for nummer, primtall in enumerate(primliste, start = 1):
    print(f"Primtall nummer {nummer} er {primtall}")

Oppgave 2:

Endre koden fra oppgave 1, slik at også nummeret på oddetallet skrives ut, sammen litt forklarende tekst. For eksempel Oddetall nummer 1 er 1, Oddetall nummer 2 er 3, og så videre.

Se løsningsforslag

Gjennomløpe med indekser

Vi kan også bruke indekser til å gjennomløpe ei liste. Vi bruker da range() til å generere de aktuelle indeksene, og refererer så til elementene i lista ved å angi indeksene i klammeparentes. Dette er illustrert i eksempel 4, som gir samme utskrift som eksempel 2 og 3.

Eksempel 4:

# Oppretter ei liste med primtall og skriver dem ut nummerert
primliste = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
for n in range(len(primliste)):
    print(f"Primtall nummer {n + 1} er {primliste[n]}")

I eksempel 4 er det 10 elementer i primliste, så vi kan generere indeksene ved å skrive range(10), noe som vil gi tallene fra 0 til 9. Men da låser vi oss til at primliste inneholder 10 elementer. Dersom vi siden legger til eller fjerner elementer, vil vi måtte bytte ut 10-tallet. Det er også fort å gjøre feil hvis vi teller antall elementer i ei liste for hånd. I stedet for å angi et fast tall som argument til range(), bruker vi derfor den innebygde Python-funksjonen len(). Brukt på ei liste, returnerer len() antall elementer i lista. Hvis ei liste, a, inneholder n elementer, vil len(a) returnere n, og range(len(a)) vil gi tallene fra og med 0 til og med n − 1, som jo er indeksene i ei liste med n elementer.

Å bruke faste verdier i stedet for dynamisk genererte verdier, slik som 10 i stedet for len(), kalles hardkoding, og er generelt noe vi bør unngå, fordi det gjør koden vår mindre fleksibel.

Noen programmeringsspråk har ikke en forin-mekanisme lik den vi har brukt i eksempel 1, 2 og 3. Da er vi nødt til å bruke indekser til gjennomløp, slik som i eksempel 4. I Python bør vi imidlertid bruke forin når vi kan, fordi det gir enklere og mer oversiktlig kode.

Det finnes imidlertid tilfeller der å basere seg på indekser for å gjennomløpe ei liste er et riktig valg, typisk hvis vi skal referere til elementer som ikke kommer etter hverandre, eller flere elementer samtidig.

Eksempel 5 viser kode som gjennomløper ei liste for å sjekke om innholdet stemmer med Fibonaccis tallfølge, der hvert tall er lik summen av de to tallene foran. Hvis for eksempel lista fibo = [1, 1, 2, 3, 5, 8, 13], vil koden skrive ut at lista inneholder Fibonaccis følge. Men hvis fibo = [1, 1, 2, 3, 5, 8, 12], vil koden skrive ut at lista ikke inneholder Fibonaccis følge, fordi 5 + 8 ikke er 12.

Eksempel 5:

# Sjekker om lista fibo inneholder Fibonaccis tallfølge
er_fibo = True
for n in range(2, len(fibo)):
    if fibo[n] != fibo[n - 1] + fibo[n - 2]:
        er_fibo = False
if er_fibo == True:
    print("Lista inneholder Fibonaccis følge.")
else:
    print("Lista inneholder ikke Fibonaccis følge.")

Koden i eksempel 5 bruker range() til å generere n som en indeks som går fra 2 til enden av lista fibo. For hver n sjekker vi så om elementet med indeks n er lik summen av de to elementene foran, det vil si de med indeks n − 1 og n − 2. Hvis dette ikke er tilfelle, settes den boolske variabelen er_fibo til False. Hvis hele lista blir gjennomløpt uten at er_fibo, som i utgangspunktet er True, er blitt satt til False, inneholder lista Fibonaccis følge. En variabel som er_fibo, som brukes til å signalisere en tilstand, kalles et flagg.

Vi burde strengt tatt også sjekket om de to første elementene begge er 1, men vi droppet det for oversiktens skyld.

Koden i eksempel 5 kan for øvrig skrives bedre, slik det beskrives i artikkelen om break.

Oppgave 3:

Endre koden fra oppgave 1 slik at den bruker indekser til å skrive ut lista med oddetallene i omvendt rekkefølge.

Se løsningsforslag

Hvis vi skal endre elementene ei liste mens vi gjennomløper den, må vi også bruke indekser, som i eksempel 6, der vi kvadrerer alle elementene i ei liste.

Eksempel 6:

# Kvadrerer elementene i lista demo
demo = [1, 2, 3, 4]
for n in range(len(demo)):
    demo[n] **= 2

Alternativt kan vi skrive koden i eksempel 6 som i eksempel 7, der vi bruker enumerate() til å generere indeksene.

Eksempel 7:

# Kvadrerer elementene i lista demo
demo = [1, 2, 3, 4]
for n, tall in enumerate(demo):
    demo[n] = tall**2

SkjermfilmSe film om lister

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Programmeringsspråket JavaScript har en mekanisme tilsvarende forin, som heter forof. Programmeringsspråket C har imidlertid ingen slik mekanisme. I C må vi basere oss på å generere en følge med tall og bruke disse som indekser.

Lister i Python Tutor

Bildet under viser hvordan ei liste illustreres i Python Tutor. Verdien til liste-variabelen partall vises som ei pil som peker på elementene i lista. Oppe til venstre i hvert element står de tilhørende indeksene. Vi ser at indekseringen starter på 0.

Visning av lister i Python Tutor

Oppgave 1:

Forsøk å forutse hva som vil skje i Python Tutor når du kjører koden under, linje for linje.

kvadrattall = []
for n in range(1, 5):
    kvadrattall.append(n**2)

Legg så koden under inn i Python Tutor, og undersøk om du har rett.

Se løsningsforslag