Kapittel 4 Lister
Godt jobbet med betingede setninger i forrige kapittel! Du kommer til å bruke betingede setninger gjennom hele boken. Nå skal vi se på lister som er en ny datatype. Denne datatypen er en beholder for forskjellige biter med informasjon. De fleste kompliserte programmer bruker lister eller andre beholdere for å holde orden på større mengder med informasjon. Det å bli godt kjent med lister er en ypperlig anledning til å lære om konsepter som indeksering, modifisering, og sortering. Mer om dette etter hvert!
4.1 Introduksjon - Lagring av relaterte biter med informasjon?
I mange situasjoner vil du sitte med flere biter informasjon som er relaterte til hverandre. Her er et par eksempler:
I en lottotrekning trekkes det for eksempel 6 hovedtall sammen med 1 tilleggstall av en gitt tallmengde. Det vil si at det er nødvendig å holde orden på 7 biter med informasjon. Vi kan lage 7 separerte variabler for dette som holder heltall, men det er veldig tungvint.
I en SMS-tråd mellom 2 personer så er det en historikk med meldinger som begge har sendt. Dersom Anne og Anine har sendt kjærlighetserklæringer til hverandre gjennom et par måneder, blir det fort 1000 tekststrenger som skal lagres. Her vil det å opprette 1000 forskjellige variabler som holder strenger være veldig rotete. Merk at i motsetning til lottotrekningen, vil antall meldinger i en SMS-tråd stadig øke etter hvert som Anne og Anine sender flere meldinger.
Det er mulig å bruke sensorer på busser til å overvåke hvor mange personer som går av og på bussen på forskjellige stopp. Hvis du tenker på bussystemet i en storby, så er det mange stoppesteder og mange busser, så dette blir en stor mengde informasjon. Et stopp av en buss må blant annet lagre antall passasjerer som gikk på bussen, antall som gikk av bussen, og tidspunktet dette skjedde på. Her involverer informasjonen flere forskjellige datatyper.
I alle de tre eksemplene ovenfor så hadde vi hatt god nytte av lister40. Dette er en datatype i Python som vi kan bruke som en beholder til å lagre forskjellige biter med informasjon. I eksempelet med lottotrekning, så kunne vi skrevet følgende kode for å holde på vinnertallene:
Her har vi skrevet en liste hovedtall som inneholder tallene 4, 8, 15, 16, 23, og 42. Merk at vi bruker klammeparentesene [ og ] når vi skriver lister, fremfor de runde parentesene ( og ) som brukes med funksjoner. Vi har lagret tilleggstallet som et vanlig heltall i variabelen tilleggstall, siden denne skiller seg ut fra de andre. Etter vi har lært mer om lister i dette kapittelet kan vi behandle alle lottotallene over med enkelhet i Python. Hadde vi ikke brukt lister måtte vi skrevet kode som dette:
første_hovedtall = 4
andre_hovedtall = 8
tredje_hovedtall = 15
fjerde_hovedtall = 16
femte_hovedtall = 23
sjette_hovedtall = 42
tilleggstall = 19Dette er irriterende mange linjer med kode, og dette gjør behandling av data vanskelig. Eksemplene med SMS-tråder eller sensorer på busser hadde vært helt håpløst å lage på denne måten. Dette viser hvorfor lister er så viktige! Vi skal først gå gjennom litt grunnleggende hvordan du kan jobbe med lister, og deretter se på mer avanserte egenskaper.
4.2 Grunnleggende arbeid med lister
La oss først forstå hvordan vi kan arbeide med lister. Som vi så ovenfor kan vi enkelt opprette lister slik:
bynavn = ['Oslo', 'Bergen', 'Trondheim', 'Fredrikstad']
har_byråd = [True, True, False, False]
tilnærming_til_pi = [
3,
3.1,
3.14,
3.141,
3.1415
]
tom_liste = []Ved å studere eksemplene ovenfor kan du trekke noen slutninger:
Lister kan inneholde forskjellige antall elementer. Listen
bynavnhar 4 elementer, mens listentilnærming_til_pihar 5 elementer. Til slutt ser vi at listentom_listeikke inneholder noen elementer. Dette kalles en tom liste41.Lister kan ha gjentakende elementer. I listen
har_byrådhar vi gjentatt bådeTrueogFalseto ganger. Merk også at denne listen gir bare mening i sammenheng med listen over, siden Oslo og Bergen er byer med byråd. Noen lister må knyttes opp mot annen informasjon for å bli tolket riktig.Listen
tilnærming_til_piinneholder både heltall og flyttall. En liste i Python kan dermed inneholde forskjellige datatyper. I tillegg ser vi i listentilnærming_til_piat det er gyldig å skrive hvert element på en egen linje om vi ønsker dette. Dette gjør lengre lister mer leselige.
En viktig egenskap til en liste er hvor mange elementer den har. Dette kan vi jo bare telle når det er få elementer, men lister har noen ganger flere tusen eller til og med millioner med elementer. Vi kan bruke funksjonen len() for å finne lengden til en liste:
bynavn = ['Oslo', 'Bergen', 'Trondheim', 'Fredrikstad']
print(f'Listen har {len(bynavn)} elementer.')Du husker kanskje fra kapittel 2 at vi også kunne bruke funksjonen len() til å finne lengden til en streng. Vi vil senere i boken lære om andre datatyper der funksjonen len() også gir oss en beskrivelse av lengde.
Du kan sjekke om en verdi er med i en liste ved å bruke nøkkelordet in slik:
bynavn = ['Oslo', 'Bergen', 'Trondheim', 'Fredrikstad']
print('Oslo' in bynavn)
print('Molde' in bynavn)Som du ser når du kjører koden over vil du først skrive ut True og deretter False til terminalen. Du kan bruke nøkkelordet in til å kombinere lister med betingede setninger slik:
bynavn = ['Oslo', 'Bergen', 'Trondheim', 'Fredrikstad']
if 'Bergen' in bynavn:
print('Dette er vel en toppliste over norske byer, ikke sant?') For at lister skal være nyttig må vi kunne hente ut elementer, endre elementer i lister, og legge til nye elementer. La oss først vise hvordan vi kan hente ut elementer:
bynavn = ['Oslo', 'Bergen', 'Trondheim', 'Fredrikstad']
hovedstad = bynavn[0]
uoffisiell_hovedstad = bynavn[1]
print(f'Det første elementet er {hovedstad}.')
print(f'Det andre elementet er {uoffisiell_hovedstad}.')
print(f'Det tredje elementet er {bynavn[2]}.')
print(f'Det fjerde elementet er {bynavn[3]}.')Her skriver vi ut de fire elementene til terminalen. De to første elementene i listen blir lagret som egne variabler, mens de to siste elementene blir bare direkte skrevet ut. Hva som er mest nyttig avhenger av om du skal behandle elementene videre eller ikke.
En ting som umiddelbart bør ryste deg er at vi henter ut det første elementet 'Oslo' ved å skrive bynavn[0]. Burde det ikke være bynavn[1] siden det er det første elementet? Nei! Dette er viktig å få med seg. Python nummererer lister fra og med 0. Det betyr at det første elementet kan hentes med bynavn[0], det andre med bynavn[1], og så videre.
Når vi skriver bynavn[0] så sier vi at 0 er indeksen42 eller posisjonen43. Når vi skriver kode som bynavn[0] så er det vanlig å si at vi indekserer listen bynavn i indeksen 0. Dermed vil indeksering av bynavn med indeks 3 gi ut 'Fredrikstad'. Dette blir du trygg på etter hvert!
Forskjellige programmeringsspråk må gjøre valget om de ønsker å begynne å indeksere lister med 0 eller 1. Det er kanskje overraskende at de fleste programmeringsspråk, med unntak av for eksempel MATLAB, Pascal, og R, starter å indeksere med 0 fremfor 1. Det er naturlig for mennesker å telle fra 1 og oppover, og dermed kan dette være litt forvirrende i begynnelsen. Det er likevel gode grunner til å starte indeksering på 0 slik Python gjør det.
Det er alltids gøy å prøve å ødelegge litt. Hva skjer når vi prøver å hente ut et element med indeks 1000 når dette åpenbart ikke eksisterer:
bynavn = ['Oslo', 'Bergen', 'Trondheim', 'Fredrikstad']
print(f'Lurer på hva dette er: {bynavn[1000]}.')Når du kjører koden overfor vil du treffe på en IndexError. Dette er en feil som forteller oss at vi prøver å benytte oss av en indeks som er ugyldig. Når det å indeksere fra og med 0 er uvant for deg skjer det fort en IndexError.
I tillegg til å hente ut elementer fra en liste er det nyttig å endre elementene i listen. Tenk deg at jeg ikke ønsker å ha med 'Fredrikstad' i listen, men har heller lyst på 'Hamar'. Da kan jeg bare direkte si at elementet i posisjon 3 skal ha denne verdien:
bynavn = ['Oslo', 'Bergen', 'Trondheim', 'Fredrikstad']
print(f'Den originale listen er: {bynavn}')
bynavn[3] = 'Hamar'
print(f'Den nye listen er: {bynavn}')Her ser du at vi kan endre elementene i listen slik vi ønsker. Vi bare indekserer listen i den posisjonen vi ønsker å endre, og deretter setter resultatet til en ny verdi. Dette endrer ikke lengden til listen vi har, men bare hva elementene i listen er. I den neste seksjonen skal vi se hvordan vi kan gjøre lister større eller mindre ved å legge til og trekke fra elementer.
4.3 Forandring av størrelsen til en liste
Listene vi har jobbet med så langt har hatt en fastsatt lengde. Denne lengden ble bestemt når vi opprettet listen. Ofte er det derimot nødvendig å legge til eller trekke fra elementer i en liste. Her er to eksempler:
Tenk deg en liste som har titler på norske sanger med over 200.000 månedlige avspillinger på Spotify. De fleste sanger faller i popularitet over tid, mens nye sanger dukker opp plutselig. Derfor vil elementer både bli lagt til og trukket fra listen. Antallet elementer i listen vil også variere, og kan gå opp eller ned fra en måned til en annen.
Tenk deg en liste som representerer tilgjengelige kurs på en utdanningsinstitusjon som Universitetet i Bergen. Nye kurs vil bli dannet ettersom teknologiske og samfunnsmessige endringer krever ny kompetanse i befolkningen. Andre kurs vil til slutt bli avviklet dersom det ikke lenger er stort nok behov for å beholde kurset. Listen vil altså variere i størrelse over tid.
På grunn av dette trenger vi å forstå hvordan vi kan legge til nye elementer i en liste og fjerne eksisterende elementer. La oss starte med å legge til nye elementer i en liste.
4.3.1 Legge til elementer
Vi skal se på to metoder vi kan bruke for å legge til elementer i en liste. Husk fra seksjon 2.4 at metoder er funksjoner som er spesifikt tilkoblet en datatype. Vi skal se på to listemetoder:
Metoden
.append()legger på et enkelt element på slutten av listen. Dette er den mest vanlige måten å legge på nye elementer i en liste.Metoden
.insert()legger på et enkelt element på en spesifikk posisjon i en liste. Dette er nyttig dersom det nye elementet ikke skal bli lagt til på slutten av listen.
La oss gjøre noen eksempler med listemetodene .append() og .insert() slik at dette blir klarere. Anta at du har en handleliste over matvarer du skal kjøpe. Da kan du bruke metoden .append() til å legge til en ny matvare slik:
matvarer = ['Pærer', 'Saft', 'Tofu', 'Brokkoli']
print(f'Original liste: {matvarer}')
matvarer.append('Kaffe')
print(f'Modifisert liste: {matvarer}')Som du ser tar metoden .append() inn et argument som den legger til på slutten av listen. Metoden .append() returnerer None siden den endrer listen uten å opprette en ny liste. Derfor vil koden under bare skrive ut verdien None til slutt:
matvarer = ['Pærer', 'Saft', 'Tofu', 'Brokkoli']
print(f'Original liste: {matvarer}')
nye_matvarer = matvarer.append('Kaffe')
print(f'Bare verdien None: {nye_matvarer}')Begge metodene .append() og .insert() modifiserer listen direkte og returnerer ingenting. Derfor er det viktig at du ikke setter en variabel lik returverdien til disse metodene siden det bare vil gi deg None.
La oss nå se på metoden .insert(). Dette er en metode som legger til et enkelt element til listen, men på en vilkårlig posisjon. Her må vi spesifisere to biter med informasjon: Posisjonen vi ønsker å sette elementet inn i, og deretter hvilken informasjon vi ønsker å sette inn i listen. Dersom vi ønsker å sette inn strengen 'Appelsiner' i handlelisten vår, så gir det mer mening å sette den etter 'Pærer' ettersom de ligger nærme hverandre i butikken. Dette kan vi gjøre slik:
matvarer = ['Pærer', 'Saft', 'Tofu', 'Brokkoli']
print(f'Original liste: {matvarer}')
matvarer.insert(1, 'Appelsiner')
print(f'Modifisert liste: {matvarer}')Ved å spesifisere posisjon 1 i metoden .insert() ønsker vi at strengen 'Appelsiner' skal få posisjon 1 etter at innsettingen er ferdig. Siden Python teller fra og med 0 som diskutert tidligere så vil 'Appelsiner' komme på riktig plass.
I metoden .insert() så er rekkefølgen viktig. Her må posisjonen settes inn før elementet. Koden matvarer.insert('Appelsiner', 1) er altså ikke gyldig. Prøver du deg likevel vil du få en TypeError. Dette er fordi metoden .insert() forventer et heltall i det første argumentet. I mange funksjoner som tar flere argumenter så er rekkefølgen viktig.
Før vi går videre til å fjerne elementer kan det være nyttig å reflektere over følgende spørsmål: Hvorfor er det en egen metode, nemlig .append(), for å legge til elementer på slutten av lister? Er det noe spesielt med slutten av en liste? Svaret her er ja!
Lister i Python er konstruert slik at å legge til elementer på slutten av lister er veldig raskt. I systemer som er av stor størrelse, for eksempel banksystemer eller sosiale media, så har dette mye å si. Hvis du ikke har noen preferanse for hvor det nye elementet skal være i listen, så anbefaler jeg derfor å bruke metoden .append() fremfor metoden .insert().
4.3.2 Fjerne elementer
Det er flere måter å fjerne elementer i en liste. Den mest ekstreme er å fjerne alle elementene i en liste. Dette kan gjøres med metoden .clear() slik:
matvarer = ['Pærer', 'Saft', 'Tofu', 'Brokkoli']
print(f'Original liste: {matvarer}')
matvarer.clear()
print(f'Tom liste: {matvarer}')Metoden .clear() tar ingen argumenter og simpelthen fjerner alt i listen. Dette kan være nyttig dersom du er ferdig å handle og dermed skal fjerne alle matvarene.
Ofte er det mer vanlig å fjerne et enkelt element i en liste, fremfor å fjerne alt. Til dette har vi de to metodene .pop() og .remove(). Metoden .pop() fjerner et element basert på indeksen i listen, mens .remove() fjerner basert på navnet. La oss først undersøke hvordan metoden .pop() fungerer:
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Kniv', 'Visp']
redskaper.pop()
print(f'Kjøkkenredskaper etter fjerning: {redskaper}')Som du kan se så fjerner metoden .pop() det siste elementet i listen. Vi kan velge å fjerne andre elementer ved å spesifisere en indeks som argument:
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Kniv', 'Visp']
redskaper.pop(1)
print(f'Kjøkkenredskaper etter fjerning: {redskaper}')Metoden .pop() returnerer det som blir fjernet. Det kan være nyttig å binde dette til en variabel slik at vi kan gjøre noe med det videre:
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Kniv', 'Visp']
fjernet_redskap = redskaper.pop(1)
print(f'Kjøkkenredskaper etter fjerning: {redskaper}')
print(f'Det fjernede redskapet: {fjernet_redskap}')Et alternativ til å bruke metoden .pop() er å bruke nøkkelordet del. Dette gjør i bunn og grunn det samme, bare at det fjernede elementet ikke blir returnert:
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Kniv', 'Visp']
del redskaper[1]
print(f'Kjøkkenredskaper etter fjerning: {redskaper}')Jeg vil egentlig anbefale å bruke .pop() når det kommer til spesifikt fjerning av elementer i en liste basert på indeks. Nøkkelordet del kan bli brukt til mye annet enn bare lister som vi skal se senere.
Dersom du ønsker å fjerne et element i en liste, men ikke nødvendigvis vet posisjonen, så kan du bruke metoden .remove(). Denne metoden fjerner et element basert på navn fremfor indeks:
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Kniv', 'Visp']
redskaper.remove('Kniv')
print(f'Kjøkkenredskaper etter fjerning: {redskaper}')Merk deg noe viktig her: Listen redskaper har to elementer som heter 'Kniv'. Når vi bruker metoden .remove() her så vil bare den første bli fjernet. Dersom du ønsker å fjerne begge knivene fra listen så må du bruke metoden .remove() to ganger:
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Kniv', 'Visp']
redskaper.remove('Kniv')
redskaper.remove('Kniv')
print(f'Kjøkkenredskaper etter fjerning: {redskaper}')Hvis du prøver å bruke metoden .remove('Kniv') en tredje gang vil du ende opp med en ValueError. Dette er fordi det ikke er flere strenger med verdien 'Kniv' i listen redskaper igjen.
Kort oppsummert:
Vi bruker metoden
.clear()når vi ønsker å fjerne alt i en liste.Vi bruker metoden
.pop()når vi ønsker å fjerne elementer basert på posisjon.Vi bruker metoden
.remove()når vi ønsker å fjerne elementer basert på navn.
4.4 Sortering av lister
Så langt har vi tenkt på lister som en samling med verdier. Lister gir oss også en rekkefølge på elementene. Elementet som har indeks 0 er først, elementet som har indeks 1 er nummer to, osv. Dette er ikke alltid viktig, men i noen tilfeller er dette helt avgjørende:
Tenk deg at listen skal representere kinovisninger for åpningsuken til populære kinofilmer i år. Denne situasjonen har en naturlig rekkefølge der filmen med flest kinovisninger er først, filmen med nest flest kinovisninger er nummer to, osv. Vi ønsker her å ha kinovisningene i en liste som er sortert fra største til minste tall.
Tenk deg at listen skal representere byer som er reisedestinasjoner på en nettside for forlokkende reisemål. For at en bruker lett skal kunne finne sin favorittby er det vanlig at de står alfabetisk. Da må vi være sikre på at Bergen finnes under bokstaven ‘B’, mens Trondheim finnes under bokstaven ‘T’. Vi ønsker her å ha reisedestinasjonene sortert alfabetisk fra ‘A’ til ‘Å’.
I Python er det innebygde måter å sortere lister på: Det eksisterer både en metode som heter .sort() og en funksjon som heter sorted(). La oss se litt nærmere på hver av dem for å forstå forskjellen og hvordan bruke dem.
La oss begynne med metoden .sort(). Gitt en liste over kinovisninger så kan vi bruke .sort() til å sortere listen som følger:
kinovisninger = [200_000, 45_000, 265_000, 100_000, 175_000]
kinovisninger.sort(reverse=True)
print(f'Sortert liste: {kinovisninger}')Kjører du koden over så skriver vi ut en liste med sorterte kinovisninger. Vi må skrive reverse=True i metoden .sort() slik at listen blir sortert fra største til minste tall. Dette er fordi metoden .sort() sorterer fra minst til størst tall dersom ikke noe annet er spesifisert. Når du ønsker å sortere en liste fra minste til største tall kan du derfor droppe argumentet reverse=True i metoden .sort().
Legg merke til at metoden .sort() ikke returnerer en ny sortert liste, men modifiserer den eksisterende listen. I programmet ovenfor eksisterer ikke lenger den originale rekkefølgen etter at metoden .sort() blir brukt. Det er dette som er forskjellen mellom metoden .sort() og funksjonen sorted() som du kan se under:
kinovisninger = [200_000, 45_000, 265_000, 100_000, 175_000]
sortert_liste = sorted(kinovisninger, reverse=True)
print(f'Sortert liste: {sortert_liste}')
print(f'Original liste: {kinovisninger}')Her bruker vi funksjonen sorted() til å sortere kinovisningene. Vi må igjen skrive reverse=True for å sortere fra største til minste tall. Funksjonen sorted() endrer ikke den originale listen, men returnerer en ny liste. Til slutt skriver vi ut både den sorterte og den originale listen til terminalen.
Når bør du bruke metoden .sort() versus funksjonen sorted()? Fordelen med funksjonen sorted() er at du har både tilgang til den sorterte og den originale listen. Derimot mister du den originale listen når du bruker metoden .sort(). Fordelen med metoden .sort() er at den er litt mer effektiv siden den ikke trenger å opprette en ny liste. Jeg vil anbefale deg å bruke funksjonen sorted() dersom det ikke er snakk om ekstremt store lister der effektiviteten til metoden .sort() har noe å si.
Vi skal nå diskutere sortering av lister med strenger og lister med flere forskjellige datatyper. Diskusjonen blir identisk om vi bruker metoden .sort() eller funksjonen sorted(). Vi kommer derfor til å holde oss til funksjonen sorted() for å unngå å repetere diskusjonen.
Sortering av lister med strenger er intuitivt så lenge alle strengene har for eksempel stor forbokstav. Her er et enkelt eksempel med kjøkkenredskaper:
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Visp']
sortert_liste = sorted(redskaper)
print(f'Sortert liste: {sortert_liste}')Som du ser når du kjører koden så blir listen sortert alfabetisk. Dette er akkurat slik du sikkert forventer det. Se likevel hva som skjer når jeg legger til redskapet 'potetstamper' i listen. Hvordan tror du listen redskaper nå vil bli sortert?
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Visp', 'potetstamper']
sortert_liste = sorted(redskaper)
print(f'Sortert liste: {sortert_liste}')Kjører du koden så ser du at strengen 'potetstamper' ble sortert helt sist i listen. Hva er det som foregår her? I Python så kommer alle de store bokstavene før de små bokstavene. Det går altså
\[A, B, C, \dots, X, Y, Z, a, b, c, \dots, x, y, z.\]
Så når vi sammenligner strengene 'Kniv' og 'potetstamper' så vil Python avgjøre at 'Kniv' er minst siden 'K' kommer før 'p'. Så i listen over må vi sørge for at 'potetstamper' er også skrevet med stor forbokstav:
redskaper = ['Kniv', 'Ostehøvel', 'Vinglass', 'Visp', 'Potetstamper']
sortert_liste = sorted(redskaper)
print(f'Sortert liste: {sortert_liste}')Dersom du prøver å sortere en liste bestående av forskjellige datatyper kan dette fort skjære seg:
blandet_drops = ['Kniv', 113, 'Vinglass', True]
sortert_liste = sorted(blandet_drops)
print(f'Sortert liste: {sortert_liste}')Koden over vil gi en TypeError når du kjører den. Dette er fordi det ikke er mulig å sammenligne strengen 'Kniv' med heltallet 113. Vi får den samme feilen dersom vi prøver direkte å sammenligne størrelsen på dem:
Det er likevel lister med blandinger av datatyper som går greit å sortere. Et eksempel er lister som består av heltall og flyttall:
betalinger = [149, 172.50, 250, 159.90]
sortert_liste = sorted(betalinger)
print(f'Sortert liste: {sortert_liste}')Kjører du koden over så ser du at dette går helt fint. Dette er fordi det er mulig å sammenligne heltall og flyttall med sammenligningsoperatorene <, <=, >, og >=. Når du er usikker på om en liste kan sorteres så prøv om datatypene i listen kan sammenlignes først.
Til slutt er det ofte at man ønsker å finne det største eller minste elementet i en liste. Kanskje du ønsker å se den største og minste betalingen i eksempelet ovenfor? Her kan du bruke sortering sammen med indeksering:
betalinger = [149, 172.50, 250, 159.90]
sortert_liste = sorted(betalinger)
print(f'Minste betaling: {sortert_liste[0]}')
print(f'Største betaling: {sortert_liste[len(sortert_liste) - 1]}')Her sorterer vi først listen med funksjonen sorted(). Siden listen nå er sortert med minste betaling først kan vi finne den minste betalingen ved å hente ut elementet med indeks 0.
For å hente ut den største betalingen må vi hente ut elementet på slutten av listen. Dette elementet har indeks len(sortert_liste) - 1. Man skulle kanskje tro at dette elementet har indeks len(sortert_liste), men vi må huske at Python indekserer fra og med 0 og ikke fra og med 1. Derfor må vi trekke fra 1 og vi ender opp med at indeksen til det siste elementet i listen er len(sortert_liste) - 1.
Det å hente ut det største og minste elementet i lister er så vanlig at Python har egne innebygde funksjoner for dette som heter max() og min(). Du kan bruke dette i stedet for å gjøre koden litt enklere:
4.5 Negativ indeksering og slicing
Vi har jobbet mye med å indeksere lister så langt i kapittelet. Nå skal vi ta opp to symbolske hjelpemidler, nemlig negativ indeksering og slicing, som hjelper oss med å indeksere enda mer effektivt.
4.5.1 Negativ indeksering
Anta at du har en handleliste. Hvordan kan du hente ut det siste elementet eller det nest siste elementet? Vi har lært at funksjonen len() kan bistå med dette:
matvarer = ['Pærer', 'Saft', 'Tofu', 'Brokkoli']
siste_element = matvarer[len(matvarer) - 1]
nest_siste_element = matvarer[len(matvarer) - 2]Dette går jo helt greit, men det er veldig lett å gjøre feil her. I Python kan vi bruke negative indekser for å hente de siste elementene fra en liste. Koden under gjør akkurat det samme som koden tidligere på en mer lettbeint måte:
matvarer = ['Pærer', 'Saft', 'Tofu', 'Brokkoli']
siste_element = matvarer[-1]
nest_siste_element = matvarer[-2]For å trekke ut det siste elementet i listen matvarer så skriver vi matvarer[-1]. Det nest siste elementet kan hentes ut ved å skrive matvarer[-2]. Som du sikkert forstår så kan du fortsette dette til å hente ut det tredje siste elementet og så videre. Dette kalles negativ indeksering44. Negativ indeksering er ganske spesifikt til Python siden de fleste programmeringsspråk ikke støtter dette.
Negativ indeksering blir ofte brukt sammen med listemetoder. Koden under bruker metoden .pop() til å fjerne det nest siste elementet i listen matvarer ved å bruke negativ indeksering:
4.5.2 Slicing
Vi har så langt holdt oss til å jobbe med et enkelt element i en liste av gangen. Vi har hentet ut et element, endret et element, lagt til et element, eller slettet et element i en liste. I noen situasjoner er det nyttig å kunne jobbe med flere elementer i en liste samtidig. Dette kan vi gjøre med teknikken slicing45.
La oss se på et eksempel for å forstå slicing. Tenk deg at vi har en liste drikkevarer som representerer forskjellige drikkevarer. De tre første elementene i listen er alkoholfrie, mens de siste elementene er med alkohol. Hvordan kan vi trekke ut de tre første elementene i listen for å jobbe videre med dem? Før vi har lært slicing må vi gjøre noe a la dette her:
drikkevarer = ['Kaffe', 'Te', 'Melk', 'Vin', 'Øl']
alkoholfrie_drikkevarer = []
alkoholfrie_drikkevarer.append(drikkevarer[0])
alkoholfrie_drikkevarer.append(drikkevarer[1])
alkoholfrie_drikkevarer.append(drikkevarer[2])
print(f'De alkoholfrie drikkevarene: {alkoholfrie_drikkevarer}')Her lager vi en ny tom liste som heter alkoholfrie_drikkevarer. Deretter legger vi til de tre første elementene i drikkevarer til denne listen med metoden .append(). Til slutt skriver vi ut alkoholfrie_drikkevarer til terminalen.
Dette gikk jo for så vidt fint. Likevel brukte jeg mange linjer med kode for å utføre noe relativt enkelt. Vi kan forkorte dette betydelig ved å bruke slicing slik:
drikkevarer = ['Kaffe', 'Te', 'Melk', 'Vin', 'Øl']
alkoholfrie_drikkevarer = drikkevarer[0:3]
print(f'De alkoholfrie drikkevarene: {alkoholfrie_drikkevarer}')Vi bruker notasjonen drikkevarer[0:3] til å hente ut de tre første elementene i listen drikkevarer. Du kan lese dette inni deg som at vi henter ut elementene i listen drikkervarer med indeks 0 og opp til, men ikke inkludert, indeks 3. Det er kolonsymbolet : som forteller Python at vi ønsker å bruke teknikken slicing.
Den beste måten å bli mer komfortabel med slicing på er å gjøre flere eksempler. Tenk deg at du ønsker å trekke ut de alkoholholdige drikkene fra listen drikkevarer. Gjør et forsøk selv før du ser på koden under:
drikkevarer = ['Kaffe', 'Te', 'Melk', 'Vin', 'Øl']
alkoholholdige_drikkevarer = drikkevarer[3:5]
print(f'De alkoholholdige drikkevarene: {alkoholholdige_drikkevarer}')Her må vi skrive drikkevarer[3:5] siden vi ønsker å begynne fra indeks 3 og ønsker å hente opp til, men ikke inkludert, posisjon 5. Dette vil sikre oss at vi får med de to elementene med indeks 3 og 4 som ønsket.
I eksemplene over kan du faktisk skrive det enda enklere. I slicing-notasjon kan du utelate tallene dersom du ønsker å hente ut fra enden av listen. Så vi kan i begge tilfellene korte koden ned bittelitt:
drikkevarer = ['Kaffe', 'Te', 'Melk', 'Vin', 'Øl']
alkoholfrie_drikkevarer = drikkevarer[:3]
alkoholholdige_drikkevarer = drikkevarer[3:]
print(f'De alkoholfrie drikkevarene: {alkoholfrie_drikkevarer}')
print(f'De alkoholholdige drikkevarene: {alkoholholdige_drikkevarer}')Merk at vi har skrevet drikkevarer[:3] fremfor drikkevarer[0:3] her. Det er fordi vi ønsker å hente fra starten av listen, og da kan vi droppe tallet før kolonsymbolet :. På samme måte har vi skrevet drikkevarer[3:] fremfor drikkevarer[3:5]. Det er fordi vi ønsker å hente til slutten av listen, og da kan vi droppe tallet etter kolonsymbolet :.
Ofte går negativ indeksering og slicing hånd i hånd. Tenk deg at du ønsker å trekke ut alle elementene i en liste bortsett fra det første og det siste elementet. Da kan negativ indeksering sammen med slicing være redningen:
drikkevarer = ['Kaffe', 'Te', 'Melk', 'Vin', 'Øl']
utvalgte_drikkevarer = drikkevarer[1:-1]
print(f'Ingen kaffe og øl: {utvalgte_drikkevarer}')Studer koden over og overbevis deg selv om at utvalgte_drikkevarer henter ut de riktige elementene. Negativ indeksering gjør at drikkevarer[1:-1] er det samme som drikkevarer[1:len(drikkevarer) - 1]. Siden lengden på listen er 5 så er dette igjen det samme som drikkevarer[1:4]. Dette henter ut elementene med indeks 1, 2, og 3, som er det vi ønsket.
Både negativ indeksering og slicing er begge bare snarveier som hjelper oss med å skrive enklere kode. Du kan alltids skrive det ut på andre måter som vi har sett. Likevel er de svært nyttige for å skrive kode som er enkel å forstå og enkel å lese. Jeg anbefaler på det sterkeste at du gjør deg komfortabel med å bruke både negativ indeksering og slicing.
4.5.3 Strenger og lister
Det vil kanskje overraske deg at strenger har en del til felles med lister. Det er mulig å bruke både vanlig indeksering, negativ indeksering, og slicing på strenger også. Her er et enkelt eksempel som viser dette:
tv_program = 'Grevinnen og hovmesteren'
første_bokstav = tv_program[0]
siste_bokstav = tv_program[-1]
hovmesteren = tv_program[13:]Både lister og strenger er datatyper som blir kalt sekvenstyper46 i Python. De lagrer biter med informasjon i en sekvens, slik at det er mulig å bestemme rekkefølgen på elementer. Alle sekvenstyper har en del til felles:
Sekvenstyper støtter indeksering, negativ indeksering, og slicing.
Sekvenstyper støtter bruk av funksjoner som
len(),max(), ogmin().Sekvenstyper støtter å sjekke om et element er med i dem ved å bruke notasjonen
x in sderxer et element ogser en sekvens.
Likevel er det viktig å forstå at det fortsatt er forskjeller mellom to datatyper selv om de begge er sekvenstyper. Hadde alle sekvenstyper vært helt like hadde det jo ikke vært noe poeng i å ha flere av dem.
En forskjell mellom lister og strenger er at lister kan lagre mye mer variert data som heltall, flyttall, og sannhetsverdier. Vi skal til og med se i neste seksjon at vi kan legge lister inni andre lister. Dette er ikke mulig med strenger.
En annen forskjell på lister og strenger er at du kan endre verdien til elementer i lister. Du kan faktisk ikke endre verdien til elementene i en streng. Koden under vil gi deg en TypeError siden strenger ikke støtter endring:
Du kan fortsatt legge sammen strenger og lage nye strenger. Likevel kan ikke strengene du allerede har opprettet bli endret. Dette er en bevisst designbeslutning i Python for å hindre at problematiske feil oppstår.
4.6 Lister inni andre lister
Så langt har vi jobbet med lister som inneholder heltall, flyttall, sannhetsverdier, og strenger. Det er ingenting som hindrer oss i å legge lister som elementer inni andre lister. Dette høres kanskje litt merkelig ut første gangen du hører det. Likevel er lister inni andre lister overraskende nyttig.
La oss ta et eksempel der vi skal representere varelageret til en butikk. Vi må representere navnet på varen, prisen på varen, og hvor mange eksemplarer av varen vi har igjen på varelageret. Her er et forenklet scenario med tre varer:
solkrem = ['Solkrem', 39.90, 180]
lenestoler = ['Lenestol', 249.90, 7]
strykejern = ['Strykejern', 69.90, 26]Dersom vi velger å lage en ny variabel for hver vare blir det til slutt ekstremt mange variabler vi oppretter. Dette gjør det også vanskelig å behandle dem i fellesskap. Vi kan heller lage en stor liste som representerer varelageret:
Her inneholder listen varelager andre lister igjen. Det som tidligere var representert med listen solkrem har nå blitt det første elementet i listen varelager.
Når man jobber med lister inni andre lister så er det egentlig ingenting nytt. Alt du har lært tidligere i kapittelet gjelder. Likevel synes mange dette er litt vanskelig i begynnelsen, så la oss gå gjennom et par eksempler. Hvis jeg ønsker å hente ut det første elementet i listen varelager så kan jeg skrive:
varelager = [
['Solkrem', 39.90, 180],
['Lenestol', 249.90, 7],
['Strykejern', 69.90, 26]
]
solkrem_info = varelager[0]
print(f'Første element: {solkrem_info}')Her blir det første elementet ['Solkrem', 39.90, 180] i listen varelager skrevet ut til terminalen. Videre kan du behandle den akkurat slik du har gjort tidligere ved å for eksempel trekke ut prisen til solkrem slik:
varelager = [
['Solkrem', 39.90, 180],
['Lenestol', 249.90, 7],
['Strykejern', 69.90, 26]
]
solkrem_info = varelager[0]
pris_solkrem = solkrem_info[1]
print(f'Prisen til solkrem: {pris_solkrem}')Her ser du at vi har trukket ut prisen til solkrem i to separate steg. Det er også mulig å kombinere stegene i en enkelt linje slik:
varelager = [
['Solkrem', 39.90, 180],
['Lenestol', 249.90, 7],
['Strykejern', 69.90, 26]
]
pris_solkrem = varelager[0][1]
print(f'Prisen til solkrem: {pris_solkrem}')Her henter vi først ut listen som gir informasjonen om solkremproduktet med varelager[0]. Deretter blir umiddelbart elementet med indeks 1 trukket ut herfra når vi skriver varelager[0][1]. Dette er prisen til solkremen. Å jobbe med lister inni andre lister gjør at du må holde tungen rett i munnen!
Et konsept som lister inni andre lister er bra til å fange opp er et todimensjonalt rutenett. Når du spiller sjakk så spiller vi på et 8 x 8 rutenett, der vi til sammen har 64 posisjoner som brikkene våre kan være på. Fremfor å bare lagre dette som 64 elementer i en liste så kan vi lage en liste for hver rad i sjakkbrettet. Deretter kan vi beskrive sjakkbrettet som en samling av 8 rader:
sjakkbrett = [
['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1'],
['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2'],
['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3'],
['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4'],
['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5'],
['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6'],
['A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7'],
['A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8'],
]Vi skal se i kapittel 7 når vi skal gjøre det store prosjektet i del 1 av boken at lister inni andre lister vil være svært nyttig.
4.7 Prosjekt - Handlelisteassistent del 1
Nå skal vi igjen gå gjennom et prosjekt i fellesskap slik at det vi har lært i kapittelet kan anvendes. Dette prosjektet er oppdelt i to deler, der andre del av prosjektet skal bli gjennomgått i kapittel 6. Du må kode selv mens du leser for at du skal få mest mulig ut av prosjektene.
4.7.1 Oppgaven
Vi skal skrive en applikasjon som simulerer en handleliste. Dette skal være en applikasjon i terminalen der brukeren kan:
Legge til elementer i handlelisten.
Slette elementer i handlelisten.
Skrive ut handlelisten.
4.7.2 Forberedelse
La oss gå gjennom hva applikasjonen vår må bestå av før vi starter å kode. Vi trenger:
En liste som holder informasjonen om varene i handlelisten.
En måte å ta inn informasjon fra brukeren. Dette gjelder informasjon om nye varer til handlelisten, om varer skal slettes fra handlelisten, eller om handlelisten skal skrives ut.
Separat funksjonalitet for de tre tilfellene om å legge til varer, slette varer, eller skrive ut handlelisten.
Vi vil også se i løpet av utviklingen av handlelisten at applikasjonen vår har en grunnleggende mangel. Selv om det kan virke som vi har alt vi trenger for å skrive applikasjonen vil vi se at dette ikke stemmer. Vi skal fortsette med dette prosjektet i prosjektdelen av kapittel 6 der vi skal fullføre applikasjonen.
4.7.3 Legge til elementer i handlelisten
La oss først kun skrive kode for å legge til varer i handlelisten. Vi starter med en tom handleliste og ber brukeren legge til en enkelt vare til den:
handleliste = []
vare = input('Legg til en ny vare til handlelisten: ')
handleliste.append(vare)
print(f'Handleliste: {handleliste}')Her bruker vi funksjonen input() til å ta inn en vare fra brukeren. Deretter benytter vi listemetoden .append() for å legge til varen til handlelisten. Vi skriver også ut handlelisten slik at det er lettere å oppdage feil mens vi jobber med koden. Når vi er sikker på at koden fungerer som den skal kan vi fjerne print()-utsagnene.
Alt ser bra ut ved første øyekast. Men hva skjer dersom du kjører applikasjonen flere ganger? Tenk deg at du først kjører koden en gang og skriver inn verdien 'Eple'. Deretter kjører du koden igjen og skriver inn 'Banan'. Hva vil da listen handleliste inneholde? Siden programmet blir kjørt helt fra start igjen så vil handleliste bli satt til en tom liste ved starten av den andre gjennomkjøringen. Derfor vil handlelisten bare inneholde varen 'Banan'. Kort sagt kan vi si at programmet vårt ikke har noen hukommelse.
Dette er en kritisk feil med programmet vårt, og noe vi til slutt skal fikse i prosjektdelen av kapittel 6. Vi skal jobbe videre med programmet selv om det har mangler som vi må fikse på et senere tidspunkt. Det er svært vanlig å utvikle funksjonalitet som for øyeblikket er ufullstendig eller manglende når man koder. Å leve i denne usikkerheten kan være litt vanskelig i begynnelsen, men dette kommer seg etter hvert.
4.7.4 Slette elementer i handlelisten
La oss nå se på hvordan vi kan slette varer fra handlelisten. Vi trenger da å skille mellom når brukeren ønsker å slette varer, og når brukeren ønsker å legge til varer. Vi kan først spørre brukeren om dette slik:
handleliste = []
handling = input('Vil du legge til eller fjerne varer (L/F): ')
if handling == 'L':
vare = input('Legg til en ny vare til handlelisten: ')
handleliste.append(vare)
print(f'Handleliste: {handleliste}')
elif handling == 'F':
vare = input('Vare i handlelisten som skal fjernes: ')
handleliste.remove(vare)
print(f'Handleliste: {handleliste}')Her ber vi først brukeren om å spesifisere hvilken handling de ønsker å utføre. Når brukeren skriver inn bokstaven 'L' så er dette en forkortelse for å legge til, mens 'F' er en forkortelse for å fjerne. Skriver brukeren inn 'L' så kan vi bruke samme fremgangsmåte som tidligere. Dersom brukeren skriver inn 'F' bruker vi da listemetoden .remove() til å fjerne varen fra handlelisten.
4.7.5 Testing av funksjonalitet
Hver gang du legger til ny kode er det viktig å teste den nye funksjonaliteten. Kjører du koden over og skriver inn 'L' for å legge til en ny vare til handlelisten går alt på skinner. Men dersom du skriver 'F' for å fjerne elementer så vil du støte borti et problem. Du vil få en ValueError med en beskjed om at verdien ikke er i listen. Hvorfor det?
Dette er det samme problemet som vi støtte på tidligere i teksten. Siden listen blir satt til en tom liste for hver gang du kjører programmet vil det ikke være noe å fjerne. En måte å komme seg rundt dette problemet foreløpig er å heller begynne med en halvfull liste slik at vi kan teste om fjerningen av elementer fungerer.
handleliste = ['Eple', 'Pære', 'Chips']
handling = input('Vil du legge til eller fjerne varer (L/F): ')
if handling == 'L':
vare = input('Legg til en ny vare til handlelisten: ')
handleliste.append(vare)
print(f'Handleliste: {handleliste}')
elif handling == 'F':
vare = input('Vare i handlelisten som skal fjernes: ')
handleliste.remove(vare)
print(f'Handleliste: {handleliste}')En annen ting vi kan lure på er hva som skjer dersom brukeren ikke skriver 'L' eller 'F' på det første spørsmålet? Da vil verken if-setningen eller elif-setningen kjøre og programmet avsluttes. Dette var litt brått. Her hadde det vært fint om brukeren kunne få en beskjed om hva de har gjort galt:
handleliste = ['Eple', 'Pære', 'Chips']
handling = input('Vil du legge til eller fjerne varer (L/F): ')
if handling == 'L':
vare = input('Legg til en ny vare til handlelisten: ')
handleliste.append(vare)
print(f'Handleliste: {handleliste}')
elif handling == 'F':
vare = input('Vare i handlelisten som skal fjernes: ')
handleliste.remove(vare)
print(f'Handleliste: {handleliste}')
else:
print('Dette er ikke et gyldig input. Prøv igjen!')Det er også vanlig at brukere skriver inn små bokstaver, i vårt tilfelle 'l' og 'f', når de mener 'L' og 'F'. Slik koden er så langt vil programmet da ende opp i else-blokken. Det er mer naturlig at både 'l' og 'L' leder brukeren til if-blokken, mens både 'f' og 'F' leder brukeren til elif-blokken. For å sikre dette kan vi bruke strengmetoden .upper() slik:
handleliste = ['Eple', 'Pære', 'Chips']
handling = input('Vil du legge til eller fjerne varer (L/F): ')
if handling.upper() == 'L':
vare = input('Legg til en ny vare til handlelisten: ')
handleliste.append(vare)
print(f'Handleliste: {handleliste}')
elif handling.upper() == 'F':
vare = input('Vare i handlelisten som skal fjernes: ')
handleliste.remove(vare)
print(f'Handleliste: {handleliste}')
else:
print('Dette er ikke et gyldig input. Prøv igjen!')4.7.6 Skrive ut handlelisten
La oss legge på funksjonalitet for at brukeren kan skrive ut listen. Når handlelisten skal skrives ut så kan vi skrive den ut sortert. Dette blir da en ny mulighet som vi må legge til i programmet med en ny elif-setning:
handleliste = ['Eple', 'Pære', 'Chips']
handling = input('Legge til, fjerne, eller skrive ut varer? (L/F/S): ')
if handling.upper() == 'L':
vare = input('Legg til en ny vare til handlelisten: ')
handleliste.append(vare)
elif handling.upper() == 'F':
vare = input('Vare i handlelisten som skal fjernes: ')
handleliste.remove(vare)
elif handling.upper() == 'S':
sortert_handleliste = sorted(handleliste)
print(f'Handlelisten er: {sortert_handleliste}')
else:
print('Dette er ikke et gyldig input. Prøv igjen!')Her har jeg brukt funksjonen sorted() siden jeg ikke trenger å endre den originale listen. Dermed kan vi fortsatt huske rekkefølgen som brukeren har lagt til elementer om vi skulle trenge dette. Jeg har også fjernet print()-utsagnene vi hadde tidligere siden vi nå har egen funksjonalitet for utskrift av listen.
4.7.7 Hva som mangler
Vi har nå bygget ut funksjonaliteten til applikasjonen. Likevel er ikke programmet veldig nyttig ennå siden programmet ikke har noen hukommelse. Vi trenger en måte å fortsette å stille spørsmål slik at brukeren kan legge til flere varer, slette varer, eller skrive ut handlelisten. Det vi trenger er en løkke47. Vi kan bruke løkker til å gjenta funksjonalitet og hindre at programmet avsluttes før applikasjonen har gjort jobben sin ferdig. Du vil lære alt du trenger å vite om løkker i kapittel 5.
Vi skal likevel ikke returnere til dette prosjektet før i slutten av kapittel 6. Det er i kapittel 6 at vi skal lære hvordan vi kan skrive våre egne funksjoner. Vi kan da skrive egne funksjoner for å legge til varer, slette varer, og skrive ut handlelisten. Dette vil gjøre det enklere for oss å utvide koden til flere formål hvis vi ønsker å utvide programmet senere.
4.8 Oppgaver
Oppgave 1
Hva gjør følgende kode? Beskriv hvert steg!
danser = ['Salsa', 'Tango', 'Bachata']
danser.insert(1, 'Brudevals')
danser.remove('Tango')
danser.pop(-1)
danser.append('West Coast Swing')
danser.pop(0)Hvilke elementer inneholder listen danser til slutt?
Oppgave 2
Listen fjellhøyder beskriver høyden over havet til ulike norske fjell:
Bruk både metoden
.sort()og funksjonensorted()for å sortere listenfjellhøyderi stigende rekkefølge, og skriv ut resultatet.Hent høyden til det høyeste fjellet ved å bruke indeksering på den sorterte listen.
Hent høyden til det høyeste fjellet ved å bruke den innebygde funksjonen
max().
Oppgave 3
En distré trollmann skal på shopping, men han har rotet til rekkefølgen på de magiske ingrediensene han skal kjøpe. Handlelisten ser slik ut:
ingredienser = [
'Flaggermusvinge', 'Paddeøye',
'Trollhår', 'Drageblod',
'Frosketunge', 'Månestein'
]Trollmannen trenger de tre første ingrediensene for å lage en usynlighetsdrikk, mens de tre siste brukes til å lage en tidsreisesalve.
Bruk slicing til å hente ut de tre første ingrediensene i en ny liste som heter
usynlighetsdrikk.Bruk slicing til å hente ut de tre siste ingrediensene i en ny liste som heter
tidsreisesalve.
Oppgave 4
Det har åpnet en ny smoothiebar som serverer forfriskende drikker til en billig penge. Informasjonen om smoothiene er lagret som en liste av lister:
smoothie_meny = [
['Tropisk Drøm', 59.90, ['ananas', 'mango', 'appelsin']],
['Grønn Energi', 64.90, ['eple', 'spinat', 'lime']],
['Rød Vitaminbombe', 62.50, ['jordbær', 'rødbete', 'gulrot']]
]Hvert element i smoothie_meny inneholder informasjon om én bestemt smoothie. Her finner du informasjon om smoothiens navn, prisen, og en ingrediensliste. Din jobb er som følger:
Skriv ut navnet og prisen på hver smoothie i menyen.
En kunde spør hva som er ingrediensene i smoothien som heter Grønn Energi. Skriv ut ingrediensene i Grønn Energi på en hyggelig måte.
Smoothiebaren har blitt trendy og vil øke alle prisene med 10 kroner. Oppdater prisene i menyen.
Oppgave 5 (Utfordrende)
Gitt en liste trenger du noen ganger å lage en ny kopi av listen. Her er den mest intuitive måten å gjøre dette på:
påskedager = ['Palmesøndag', 'Skjærtorsdag', 'Langfredag', 'Påskeaften']
påskedager_kopi = påskedagerKoden over kan oppføre seg annerledes enn du kanskje forventer. Kjør koden under og se hva du får:
påskedager = ['Palmesøndag', 'Skjærtorsdag', 'Langfredag', 'Påskeaften']
påskedager_kopi = påskedager
påskedager_kopi[3] = '1. påskedag'
print(f'Kopi: {påskedager_kopi}')
print(f'Original: {påskedager}')Som du ser når du kjører koden blir den originale listen påskedager også endret. I Python vil tilordningen påskedager_kopi = påskedager når det gjelder lister bare sørge for at påskedager_kopi peker til den samme verdien som påskedager gjør. Det lages altså ikke en kopi, men begge variablene påskedager og påskedager_kopi refererer nå til samme liste. Dersom en av dem endrer innholdet i listen så vil både påskedager og påskedager_kopi peke til den nye listen.
Dersom du har lyst å lage en ekte kopi så kan du gjøre dette på minst tre måter. Prøv alle tre måtene under og sjekk at du faktisk får ekte kopier og ikke referanser til samme liste:
Bruk listemetoden
.copy()slikpåskedager_kopi = påskedager.copy()til å lage en ekte kopi avpåskedager.Bruk funksjonen
list()slikpåskedager_kopi = list(påskedager)til å lage en ekte kopi avpåskedager.Bruk slicing slik
påskedager_kopi = påskedager[:]til å lage en ekte kopi avpåskedager.
PS: Det at vi ikke lager en ekte kopi når vi skriver påskedager_kopi = påskedager har med at å kopiere lister kan være ressurskrevende. For andre datatyper som heltall, flyttall, strenger, og sannhetsverdier vil uttrykk som påskedager_kopi = påskedager gi oss en ekte kopi. I kapittel 9 skal vi lære om flere andre sammensatte datatyper der utsagn som påskedager_kopi = påskedager ikke vil gi oss ekte kopier.