Tilbake
3.1

3.1 Lister og listeoperasjoner

Lister, indeksering, slicing og de vanligste metodene — og snarveiene max/min/sum/sorted som fasiten bruker fritt.

40 min
6 oppgaver
Listerlisteoperasjoner
Din fremgang i kapitlet
0 / 6 oppgaver
Forkunnskaper

- kap. 1.3 — løkker: for, while og range. Du bør kjenne igjen at range(start, stopp, steg) stopper FØR stopp.
- kap. 1.1 — datatyper og konvertering med int() og float().

Vil du ha den samme grunnmuren i en annen innpakning først, dekker Lister det samme stoffet i et parallelt emne.

Har du aldri programmert før, er det bare to ord du trenger herfra: en variabel er et navn som peker på en verdi, og en løkke er en kodeblokk som gjentas én gang for hvert element. Alt annet forklares her.

Løkke 1 — lista som beholder (~7 min)

Rutetabellen for bybussen din har fire avganger på morgenen. Du kunne laget fire variabler — avgang1, avgang2, avgang3, avgang4 — men da må koden skrives om hver gang det kommer en avgang til, og du kan ikke gå gjennom dem med en løkke.

En liste løser dette: ett navn som peker på flere verdier i en bestemt rekkefølge. Du skriver verdiene i hakeparenteser med komma mellom.

Lista `[...]`

En liste er en ordnet samling verdier under ett navn. Rekkefølgen er en del av dataene, og den samme verdien kan stå flere ganger. Verdiene kan være av forskjellig type i samme liste, men i praksis holder du dem like.

Du skriver den som verdier i hakeparenteser, atskilt med komma: avganger = [612, 627, 642, 657]. En tom liste er [], og den er ofte startpunktet: du oppretter den tom og fyller på underveis.

`len(x)`

Gir antall elementer i lista x, som et heltall. En tom liste har lengde 0.

len er den vanligste kilden til løkkegrenser: range(len(x)) gir nøyaktig plassnumrene — indeksene — 0, 1, … opp til len(x) - 1, altså alle lovlige plasser i lista og ingen flere. Indeksering gjennomgås i løkke 2 rett under.

✏️Eksempel 1: rutetabellen som liste

Legg de fire morgenavgangene 06:12, 06:27, 06:42 og 06:57 i en liste med minutter etter midnatt, skriv ut hele lista og hvor mange avganger det er.

Klokkeslettet 06:12 er 6 * 60 + 12 = 372 minutter etter midnatt. De fire tallene legges rett inn i lista.

avganger = [372, 387, 402, 417]
print(avganger)
print(len(avganger))

Utskrift:

[372, 387, 402, 417]
4

Legg merke til hvordan Python skriver ut ei liste: med hakeparenteser og komma-mellomrom mellom elementene. På en kodesporingsoppgave må du gjengi akkurat den formen — [372, 387, 402, 417], ikke 372 387 402 417.

📝Oppgave 1

(Innstegsoppgave, sjanger B — kodesporing.) Hva skriver programmet ut? Skriv begge linjene nøyaktig slik terminalen viser dem.

priser.append(18) legger verdien 18 bakerst i lista.

priser = [39, 25, 61]
priser.append(18)
print(priser)
print(len(priser))

Løkke 2 — indeksering: å plukke ut ett element (~8 min)

Hvert element i lista har et indeksnummer, altså plassnummeret sitt. Tellingen starter på 0, ikke på 1. Første avgang er avganger[0], andre er avganger[1], og siste i en firelisteliste er avganger[3].

Det er derfor range(len(x)) passer så godt: den gir nettopp 0 til og med len(x) - 1.

`x[i]` — indeksering

Henter ut elementet på plass i i lista x. Tellingen begynner på 0, så x[0] er det første elementet og x[len(x) - 1] er det siste.

Du kan også tilordne: x[2] = 99 bytter ut elementet på plass 2. Er i større enn eller lik len(x), stopper programmet med feilen IndexError: list index out of range.

`x[-k]` — negativ indeks

Teller bakfra: x[-1] er siste element, x[-2] det nest siste. Det finnes ingen x[-0] — null er null, så x[0] er alltid det første.

Nytten er at du slipper x[len(x) - 1] for å nå slutten. x[-1] er kortere og brukes fritt i løsningsforslag.

✏️Eksempel 2: første, siste og en endring

Med avganger = [372, 387, 402, 417]: skriv ut første og siste avgang, flytt den tredje avgangen fem minutter senere, og skriv ut lista igjen.

Den tredje avgangen har indeks 2, fordi tellingen starter på 0.

avganger = [372, 387, 402, 417]
print(avganger[0], avganger[-1])
avganger[2] = avganger[2] + 5
print(avganger)

Utskrift:

372 417
[372, 387, 407, 417]

print med to argumenter setter ett mellomrom mellom dem — derfor 372 417 og ikke 372417. Den detaljen er verdt poeng på utskriftssporing.

📝Oppgave 2
Sjanger B

Hva skriver programmet ut?

maling = [4, 9, 2, 7, 5]
maling[0] = maling[-1]
maling[-2] = maling[1]
print(maling)

Løkke 3 — utsnitt (slicing) (~10 min)

Ofte vil du ikke ha ett element, men en bit av lista: de tre første avgangene, annenhver måling, eller hele lista baklengs. Det kalles et utsnitt (på engelsk slice), og skrives med kolon inne i hakeparentesene.

Dette er den enkeltkonstruksjonen som oftest dukker opp i kodesporing på dette emnet, så den skal sitte helt presist.

`x[a:b]` — utsnitt

Gir en ny liste med elementene fra og med indeks a til men ikke med indeks b. Sluttgrensa er altså eksklusiv, akkurat som i range.

Utelater du a, starter utsnittet på 0; utelater du b, går det til enden. x[:2] er de to første, x[2:] er resten, og x[:] er en kopi av hele lista. Originalen endres aldri av et utsnitt.

`x[a:b:s]` — utsnitt med steg

Samme som x[a:b], men hopper s plasser om gangen. x[::2] gir elementene på indeks 0, 2, 4 …, og x[1::2] gir dem på indeks 1, 3, 5 … — altså «annethvert element», to forskjellige varianter av det.

Hvilken av de to oppgaven mener, avgjøres av om den teller fra det første eller det andre elementet. Les oppgaveteksten to ganger her.

`x[::-1]` — snudd kopi

Negativt steg går bakover. x[::-1] gir en ny liste med elementene i motsatt rekkefølge, og lar originalen stå urørt.

Det samme trikset virker på tekst: 'stein'[::-1] gir 'niets'. Skal du derimot snu lista på plass, uten å lage en ny, bruker du x.reverse().

✏️Eksempel 3: fire utsnitt av samme liste

La tall = [8, 3, 5, 1, 9, 4]. Skriv ut de tre første, alt fra og med indeks 3, annethvert element fra indeks 1, og hele lista baklengs — og vis at originalen er uendret etterpå.

Fire utsnitt, én utskrift hver, og lista til slutt.

tall = [8, 3, 5, 1, 9, 4]
print(tall[:3])
print(tall[3:])
print(tall[1::2])
print(tall[::-1])
print(tall)

Utskrift:

[8, 3, 5]
[1, 9, 4]
[3, 1, 4]
[4, 9, 1, 5, 3, 8]
[8, 3, 5, 1, 9, 4]

Gå gjennom dem én for én: tall[:3] stopper før indeks 3, så 1-tallet er ikke med. tall[3:] begynner nettopp på indeks 3, så det er 1-tallet som er første element der. tall[1::2] tar indeks 1, 3 og 5. Og siste linje viser poenget: originalen er den samme som før — et utsnitt lager alltid en ny liste.

📝Oppgave 3
Eksamensnivå, sjanger B

Hva skriver programmet ut? Skriv alle fire linjene nøyaktig, med hakeparenteser og komma-mellomrom.

m = [10, 20, 30, 40, 50, 60, 70]
print(m[2:5])
print(m[::3])
print(m[-3:])
print(len(m[1:4]))

Løkke 4 — metodene som endrer lista (~10 min)

En metode er en funksjon som hører til et objekt, og som kalles med punktum: avganger.append(432). De fleste listemetodene endrer lista du kaller dem på, og returnerer ingenting.

Definisjonene under er flashcard-stoff — du kan trygt bla forbi dem ved førstegangslesing og komme tilbake når du pugger. Det du må ta med deg nå, er skillet mellom «endrer lista» og «gir en ny».

`x.append(v)`

Legger verdien v bakerst i lista x. Lista blir ett element lengre, og metoden returnerer None — du skriver aldri x = x.append(v).

Dette er arbeidshesten i hele faget: du oppretter resultat = [] og fyller på med append inne i en løkke.

`x.insert(i, v)`

Setter v inn PÅ plass i, og skyver resten ett hakk bakover. x.insert(0, v) legger altså verdien først.

Er i større enn lengden, havner verdien bakerst i stedet for å gi feil. Lista endres på plass, og metoden returnerer None.

`x.pop(i)`

Fjerner elementet på plass i OG returnerer det. Uten argument, x.pop(), fjernes og returneres det siste elementet.

Dette er den ene fjerne-metoden som gir deg verdien tilbake, så den brukes når du både vil ta ut og bruke et element.

`x.remove(v)`

Fjerner den FØRSTE forekomsten av verdien v — ikke alle. Metoden tar en verdi, ikke en indeks, og returnerer None.

Finnes ikke verdien i lista, stopper programmet med ValueError. Sjekk derfor med if v in x: først når du er usikker.

`x.index(v)`

Gir indeksen til den første forekomsten av v. Finnes ikke verdien, stopper programmet med ValueError.

Dette er konstruksjonen som senere lar deg finne en kolonne ved navn i stedet for å hardkode et kolonnenummer — et eksplisitt krav for full uttelling på eksamen.

`x.count(v)`

Gir antall ganger verdien v forekommer i lista, som et heltall. Er verdien ikke der, gir den 0 — den stopper altså aldri programmet.

x.count(v) er den korteste måten å telle på når du bare skal telle ÉN verdi. Skal du telle alle verdiene, trenger du en ordbok.

`x.sort()`

Sorterer lista stigende PÅ PLASS og returnerer None. Lista du kalte den på er endret etterpå; den gamle rekkefølgen er borte.

x.sort(reverse=True) sorterer synkende. Vil du ha en sortert kopi og beholde originalen, bruker du sorted(x) i stedet.

`x.reverse()`

Snur rekkefølgen i lista på plass og returnerer None. Ingen ny liste lages.

Forskjellen fra x[::-1] er nettopp der: utsnittet gir en ny, snudd liste og lar originalen stå, mens reverse() endrer originalen.

✏️Eksempel 4: rediger en avgangsliste

Rutetabellen [372, 387, 402, 417] skal endres: en ny avgang 06:02 settes inn først, avgangen 06:42 utgår, og den siste avgangen flyttes til en egen variabel og tas ut av lista. Skriv ut lista og den uttatte avgangen.

06:02 er 6 * 60 + 2 = 362 minutter, og 06:42 er 402. Merk at pop er den eneste av de tre som gir en verdi tilbake.

avganger = [372, 387, 402, 417]
avganger.insert(0, 362)
avganger.remove(402)
siste = avganger.pop()
print(avganger)
print(siste)

Utskrift:

[362, 372, 387]
417

remove(402) tar verdien 402, ikke plass nummer 402. Det er et vanlig blandingspunkt: remove tar en verdi, pop tar en indeks.

📝Oppgave 4
Sjanger G

En resirkuleringsstasjon registrerer hvilken fraksjon hvert innlevert kolli havner i. Skriv funksjonen rydd(logg, fjern) som tar imot lista logg med fraksjonsnavn og ett navn fjern, og returnerer en NY liste der alle forekomster av fjern er borte. Originalen skal være uendret etterpå.

Test den med logg = ['glass', 'papir', 'glass', 'metall'] og fjern = 'glass'.

Løkke 5 — snarveiene, og løkka som gjør det samme (~8 min)

Nå kommer den delen der dette emnet skiller seg fra mange andre programmeringskurs: du får lov til å bruke de innebygde snarveiene. Løsningsforslagene gjør det selv.

Men du skal kunne begge deler, av en praktisk grunn: max(x) gir deg den største verdien, ikke hvem den tilhører. Skal du finne den dyreste varen OG navnet på den, må du gå gjennom lista selv.

`max(x)` og `min(x)`

Gir henholdsvis den største og den minste verdien i lista. På tekstlister sammenlignes ordene alfabetisk, med store bokstaver før små.

Er lista tom, stopper programmet med ValueError. Derfor sjekker robust kode if len(x) > 0: før den bruker dem.

`sum(x)`

Legger sammen alle tallene i lista og gir summen. En tom liste gir 0, ikke feil — det er den eneste av snarveiene som tåler tom liste.

sum virker bare på tall. Er elementene lest fra fil, er de strenger, og du må konvertere dem med int() eller float() først.

`sorted(x)`

Gir en NY liste med elementene i stigende rekkefølge, og lar x stå urørt. sorted(x, reverse=True) gir synkende.

Dette er forskjellen fra x.sort(), som endrer originalen og returnerer None. Trenger du den gamle rekkefølgen senere, er sorted det trygge valget.

`v in x` — medlemskapstesten

Gir True hvis verdien v finnes i lista x, ellers False. Den brukes både som betingelse og som vakt: if navn not in resultat: er standardmåten å unngå duplikater på.

Testen ser på verdier, ikke indekser, og den stopper aldri programmet — den svarer bare False når verdien mangler.

`+` og `*` på lister
a + b gir en ny liste der b er skjøtt bakpå a; ingen av originalene endres. [0] * 4 gir [0, 0, 0, 0] — en rask måte å lage ei liste med startverdier på.

+ legger ikke sammen tallene elementvis: [1, 2] + [3] blir [1, 2, 3], ikke [4, 2]. Det er en fast felle på kodesporing.

`list(range(a, b, s))`
range gir en oppskrift på en tallrekke, ikke ei liste. list(...) gjør den om til ei ekte liste du kan skrive ut og indeksere.

Skriver du print(range(3)), får du range(0, 3) og ikke [0, 1, 2]. Skal tallrekka vises, må den pakkes i list(...).

Kopi mot alias: `b = a[:]`
b = a gir IKKE en kopi — det gir et nytt navn på den samme lista, og en endring gjennom det ene navnet synes gjennom det andre.

Vil du ha en uavhengig kopi, skriver du b = a[:] eller b = list(a). Dette er feilkode #15, aliasing, og den er vanskelig å se fordi koden ser riktig ut.

✏️Eksempel 5: dyreste vare — snarvei og løkke side om side

En prisliste for en dagligvarehandel ligger som to lister: varer med navn og priser med kroner, i samme rekkefølge. Finn den høyeste prisen, og finn hvilken vare den tilhører.

Den høyeste prisen alene er en énlinjes snarvei.

varer = ['brød', 'melk', 'kaffe', 'ost']
priser = [39, 25, 89, 61]
print(max(priser))

Utskrift:

89

Skal du også ha navnet, holder ikke max alene. Da går du gjennom indeksene og husker hvor det beste sto:

varer = ['brød', 'melk', 'kaffe', 'ost']
priser = [39, 25, 89, 61]
beste = 0
for i in range(len(priser)):
    if priser[i] > priser[beste]:
        beste = i
print(varer[beste], priser[beste])

Utskrift:

kaffe 89

En tredje vei er å bruke snarveien til å finne verdien og .index til å finne plassen:

varer = ['brød', 'melk', 'kaffe', 'ost']
priser = [39, 25, 89, 61]
topp = max(priser)
print(varer[priser.index(topp)], topp)

Utskrift:

kaffe 89

Alle tre gir full pott. Snarveien er kortest når du bare skal ha verdien; løkka er den du trenger når svaret er «hvem», og den er også den eneste som lett kan utvides til å håndtere at lista er tom. Merk at løkkevarianten starter med beste = 0, ikke med en oppdiktet minsteverdi — da slipper du å gjette hvor lave prisene kan bli.

📝Oppgave 5
Sjanger G

En værstasjon har døgnmiddeltemperaturer for en uke i lista grader. Skriv over_snittet(grader) som returnerer ei liste med de temperaturene som er høyere enn ukesgjennomsnittet.

a) Løs oppgaven med snarveiene sum og len.
b) Forklar med én setning hvorfor funksjonen må regne ut gjennomsnittet FØR løkka, ikke inne i den.

Test med grader = [4, 9, 2, 7, 5, 11, 1].

✏️Eksempel 6: aliasing — den usynlige feilen

Hva er forskjellen på b = a og b = a[:] når du etterpå endrer b?

Prøv begge deler i samme program.

a = [1, 2, 3]
b = a
b.append(99)
print(a)

c = [1, 2, 3]
d = c[:]
d.append(99)
print(c)

Utskrift:

[1, 2, 3, 99]
[1, 2, 3]

Første utskrift er poenget: a ble endret selv om du bare rørte b. b = a lager ikke en ny liste, bare et nytt navn på den gamle. I det andre tilfellet er d en ekte kopi, og c står urørt.

Regelen å ta med seg: skal en funksjon la argumentet sitt være i fred, må den jobbe på liste[:] — ikke på liste.

📝Oppgave 6
Eksamensnivå, sjanger B

Hva skriver programmet ut? Skriv alle tre linjene nøyaktig.

a = [3, 6, 9, 12]
b = a
c = a[:]
b.append(15)
c.reverse()
print(a)
print(b)
print(c)

Repetisjon — de seks setningene du bør ha med deg
API- og konstruksjonsliste

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 Norges teknisk-naturvitenskapelige universitet. Dette er ikke offisielt studiemateriell. Les mer.