Uke 7 — list / tuple / string¶
Denne uken avslutter vi med lister og tupler. Les https://automatetheboringstuff.com/2e/chapter4/ frem til «A Short Program: Conway’s Game of Life.»
Eksempler¶
Eksempel 1: Tupler¶
Tupler er litt som en liste, men bruker ()
isteden for []
. Det er noen
viktige forskjeller på tupler og lister som vi skal se på seinere. I dette
eksempelet lager vi noen tupler og ser hvordan de kan brukes.
Last ned filen her: eksempel_1_tuple.py
, og kjør koden.
# a tuple with three elements:
bergen = ("rain", 60.39, 5.32) # bergen weather, latitude, longitude
# a tuple with one element (notice the comma - what happens if you remove the comma?)
bergen_weather = ("rain",)
print("Two tuples:")
print(f"bergen = {bergen}\nbergen_weather = {bergen_weather}\n")
print("Tuple unpacking:")
weather, latitude, longitude = bergen # we can assign multiple variables to values in a tuple
print(f"weather = {weather})
print(f"latitude = {latitude})
print(f"longitude = {longitude}")
print("Lists of tuples:")
# here is a list of tuples
bergen_temp_forecast = [(16.0, "onsdag"), (14.0, "torsdag"), (13.0, "fredag")]
# we can unpack them automatically while going through the list
for temp, day in bergen_temp_forecast:
print(f"På {day} blir det {temp} grader.")
Oppgave 1¶
I uke_07_oppg_1.py
skal du skrive en funksjon som bytter ut favorittmaten
til en katt. Lag en funksjon kalt swap_tuple()
som tar som argument en tuple
med tre strenger. Den første strengen er kattens navn. Den andre strengen er
kattens personlighet. Den tredje strengen er kattens favoritmat. Du skal bytte
ut favoritmaten til "salmon"
. Funksjonen skal returnere den oppdaterte
tupelen. For eksempel, swap_tuple(("Princess Sparkle", "aloof", "tuna"))
skal returnere:
("Princess Sparkle", "aloof", "salmon")
Eksempel 2: Sekvenser¶
Her er noen eksempler på lister, tupler og strenger. Alle tre kan indekseres på den samme måten, og alle tre kan brukes i for-løkker. Vi kan også konvertere mellom disse tre sekvensene.
Last ned filen her: eksempel_2_sequence_types.py
, og kjør koden.
Skjønner du hva som skjer?
# sequence types: list, tuple, str
# list
x = [2, 3, 5, 6, 7] # list type
print(x)
print(x[1]) # index 1st position of list x
print(x[1:3]) # slice list x 1st to 3rd position
x = x + [3, 4] # add values to list x
x[1] = 999 # only for list: change element
print(x)
# tuple
y = (2, 3, 5, 6, 7) # tuple type
print(y[1]) # index 1st position of tuple y
print(y[1:3]) # slice tuple y 1st to 3rd position
y = y + (3, 4) # add values to tuple y
# y[1] = 999 # not possible to change elements
print(y)
# string
z = "23567"
print(z)
print(z[1]) # index 1st position of string z
print(z[1:3]) # slice string z 1st to 3rd position
z = z + "9876" # add to string z
# z[1] = "A" # not possible to change elements
print(z)
print("\n" * 3)
#######
# Sequences can be used interchangeably in many places:
# Can use all sequences in for loops
for e in x:
print("...", e, "...")
for e in y:
print("===", e, "===")
for e in z:
print("***", e, "***")
print("\n" * 3)
#######
# conversions between list - tuple - string
some_list = [
4,
5,
6,
7,
8,
]
some_tuple = (6, 7, 8, 9, 10, 11, 12, 13)
some_str = "Hello there"
print("Convert to list")
print(list(some_list))
print(list(some_tuple))
print(list(some_str))
print("Convert to tuple")
print(tuple(some_list))
print(tuple(some_tuple))
print(tuple(some_str))
print("Convert to str")
print(str(some_list))
print(str(some_tuple))
print(str(some_str))
Oppgave 2¶
I denne oppgaven får vi data om ukens maks temperaturer som én str
.
For eksempel kan dataen se slik ut:
"16.1 14.1 13.3 15.0 13.0 13.2 12.9" # Mandag - Søndag
I uke_07_oppg_2.py
, skriv en funksjon som heter update_weather()
og som
tar en slik streng med én ukes temperaturer og lager et tupel med temperaturene
konvertert til float
(i samme orden). For eksempel, update_weather("16.1
14.1 13.3 15.0 13.0 13.2 12.9")
skal returnere følgende tupel (husk uke 6!):
(16.1, 14.1, 13.3, 15.0, 13.0, 13.2, 12.9)
Skriv også en funksjon som heter tuesday_weather()
og som tar en tupel med
en ukes temperaturer som float
og returnerer temperaturen på tirsdagen (også
som en float
). For eksempel, tuesday_weather((16.1, 14.1, 13.3, 15.0,
13.0, 13.2, 12.9))
skal returnere:
14.1
Eksempel 3a: Foranderlig / ikke foranderlig¶
Lister, tupler og strenger er like på mange måter, hovedforskjellen er at listene kan endres, vi kaller det for «mutable». Her er noen eksempler på forskjellen mellom lister (som kan forandres), og tupler, som er ’immutable’ (som ikke kan forandres).
Last ned filen her: eksempel_3a_mutable.py
, og kjør koden. Skjønner
du hva som skjer? Hvorfor blir b
endret etter a += [999, 777]
?
Hvorfor blir b
ikke endret etter a += (999, 777)
?
# Lists are mutable, assignment works by reference
a = [2, 4, 8, 16]
b = a
c = a
d = a[:]
print(f'{a = }\n{b = }\n{c = }\n{d = }')
print('Change a:')
a += [999, 777]
# not the same as a = a + [999, 777] (why?)
#a = a + [999, 777]
print(f'{a = }\n{b = }\n{c = }\n{d = }')
print('Change b:')
b += [111, 222]
print(f'{a = }\n{b = }\n{c = }\n{d = }')
print('\n\n\n')
# Tuples (and str) are immutable, assignment works by copy
a = (2, 4, 8, 16)
b = a
c = a
d = a[:]
print(f'{a = }\n{b = }\n{c = }\n{d = }')
print('Change a:')
a += (999, 777)
print(f'{a = }\n{b = }\n{c = }\n{d = }')
print('Change b:')
b += (111, 222)
print(f'{a = }\n{b = }\n{c = }\n{d = }')
# try with str...
Eksempel 3b: Referanser¶
Nå skal vi bruke visualiseringsverktøyet på pythontutor.com for å se hvordan referanser fungerer i python med et konkret ekesempel.
Åpne lenken ovenfor og klikk «Next» for å gå trinnvis gjennom koden. Følg nøye
med på hva som skjer på hvert trinn. Hvordan er m
relatert til a
?
Hvordan forholder b
seg til m
? Hvordan forholder c
seg til m
?
Hvilke listene er det som får appended den ekstra listen i linje 9? (Du kan også laste ned
filen her: eksempel_3b_ref.py
, og kjøre koden på datamaskinen din
uten visualiseringen.)
# Understanding copies and references
from copy import copy, deepcopy
m = [[17.5, 19.1, 18.6], [20.0, 19.0, 19.5]] # measurements from 2 days
a = m
b = copy(m) # same as m[:]
c = deepcopy(m)
# we can see the differences especially when we try to append additional data to our original dataset (m) -- to which list of a, b, and/or c is this new data also appended?
m.append([16.2, 19.1, 18.6]) # add a third day's measurements to original list
# if we find an error in our measurement and want to change our original dataset m, to which copies are these changes made to as well (a, b, and/or c)?
m[1][1] = 15.2
I dette eksempelet kan vi se at m
er en liste av lister og at a
er den
samme listen av lister. Variabelen b
er en kopi av listen m
, som har
referanser til de andre listene i listen m
. Derimot så er c
helt
annerledes fra de andre: det er en ny liste, med en ny versjon av listene i
listen med de samme verdiene. Listene i c
referer ikke til de samme
listene som i m
.
Oppgave 3¶
La oss nå prøve en oppgave som viser mutabilitet og referanser, som ligner på dette eksemplet. Som før, om du blir sittende fast, kan du lese gjennom dette eksemplet igjen for å få litt hjelp.
Du har et dataset som inneholder de forutsagte makstemperaturene fra mandag til
lørdag denne uken (se nedenfor). Men du fant ut at den forutsagte temperaturen
på torsdagen ikke var riktig. Makstemperaturen skal bli 12.0. Du vil gjerne korrigere
den, men vil heller gjøre det med en kopi av originalen som lar originalen være
uendret. I oppgaven uke_07_oppg_3.py
skriv en funksjon som heter
adjust_daily_temps()
og som endrer torsdagens temperatur til 12.0
, og
returnerer det oppdaterte resultatet. Resultatet må være en tuple som
originallisten.
(
("mandag", 16.0),
("tirsdag", 13.0),
("onsdag", 14.0),
("torsdag", 13.0),
("fredag", 15.0),
("lørdag", 13.0),
)
Så med dataen ovenfor ville adjust_daily_temps()
returnert følgende tupel:
(
("mandag", 16.0),
("tirsdag", 13.0),
("onsdag", 14.0),
("torsdag", 12.0),
("fredag", 15.0),
("lørdag", 13.0),
)
Eksempel 4: zip()¶
zip()
er en innebygd funksjon som «zipper» sammen sekvensene som blir gitt
inn og returnerer en liste av tupler. En sekvens kan f.eks. være en liste,
streng eller en tuple. zip
tar det første elementet fra hver sekvens og legger
de sammen i en tuple, og så det andre elementet i hver sekvens og legger de
sammen osv. Om sekvensene har ulik lengde, er det den korteste sekvensen som
bestemmer lengden til zip()
-outputet.
Last ned filen her: eksempel_4_zip.py
, og kjør koden.
# zip() tuples of same size
tup = ["cat", "dog", "cow"]
tup2 = ["meow", "woof", "moo"]
zip_tup = zip(tup, tup2)
# A zip object must be converted to list or tuple to be printed as a list or tuple.
print(zip_tup)
print(list(zip_tup))
# ...but it can be used directly in a loop:
for animal, sound in zip(tup, tup2):
print(f"<<{sound}>> says the {animal}")
print("\n------------------------\n")
# zip() list of different size
list1 = ["a", "b", "c", "d"]
list2 = [1, 2, 3]
zip_list = zip(list1, list2)
for t in zip_list:
print(t)
# to revert a zip, you can use * (see the explanation in week 06)
reverted = zip(*zip_list)
print(reverted)
Oppgave 4a¶
I denne oppgaven får vi gitt to tupler med navn, personlighet og favorittmat til
to katter. I filen uke_07_oppg_4a.py
, skriv en funksjon som heter
tuple_repack()
og tar to tupler med kattinformasjon og returnerer en liste
med kattenes personligheter (i samme orden). For eksempel,
tuple_repack(("Princess Sparkle", "aloof", "tuna"), ("Mr Cat", "energetic",
"cream"))
skal returnere følgende liste
["aloof", "energetic"]
TIPS: Du kan bruke zip()
og få ut resultatet derfra.
Oppgave 4b¶
I denne oppgaven blir vi igjen gitt en tuple med forutsagte temperaturer i en
uke. I filen uke_07_oppg_4b.py
, skriv en funksjon som heter
data_reorganize()
og som zipper tuplen dataen til en ny tuple som inneholder
dagene som en tuple og temperaturene some en annen tuple. Funksjonen skal den
resulterende omorganiserte tupelen. For eksempel, om data_reorganize()
blir
gitt følgende tupel:
(
("mandag", 16.0),
("tirsdag", 13.0),
("onsdag", 14.0),
("torsdag", 13.0),
("fredag", 15.0),
("lørdag", 13.0),
)
så skal den returnere følgende tupel:
(
('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag'),
(16.0, 13.0, 14.0, 13.0, 15.0, 13.0)
)
Eksempel 5: enumerate()¶
Den innebygde funksjonen enumerate()
er et alternativ til å bruke
range(len(myList))
med en for-løkke for å få indeksen til
elementene i listen.
På hver iterasjon av løkken vil enumerate()
returnere to verdier: (1) indeksen
til elementet i listen og (2) selve elementet i listen.
Last ned filen her: eksempel_5_enum.py
, og kjør koden. Hva er
forskjellen mellom disse to? Hvilken er lettere for deg å forstå?
daily_temp_values = [16.0, 13.0, 14.0, 13.0, 15.0, 13.0]
# One way to get indices/values
for i in range(len(daily_temp_values)):
print(f"Index {i} in daily_temp_values is {daily_temp_values[i]}")
print("\n" * 2)
# Using enumerate:
for index, temp in enumerate(daily_temp_values):
print(f"Index {index} in daily_temp_values is {temp}")
Oppgave 5¶
Du har en database med målinger hentet fra en sonde som måler vindhastighet.
Sonden registrerer vindhastighet hver time. Hver 12. time
kalibreres sonden. I uke_07_oppg_5.py
skriv en funksjon som heter
calibration_readout()
og som tar en liste med float
som argument
(vindhastighetene). Anta at den første verdien i listen er målet i løpet av en
kalibreringstime. Funksjonen skal bruke enumerate()
for å returnere listen
med vindhastigheter men hvor alle verdiene som er fra kalibreringstimer er
byttet ut til en tuple med første verdien "Calibration hour"
og andre
verdien vindhastigheten. For eksempel, om calibration_readout()
brukes på
følgende liste:
[3.0, 3.2, 3.3, 3.2, 3.0, 3.1, 3.5, 5.0, 5.0, 4.9, 4.0, 3.0, 2.9, 2.2]
så skal den returnere følgende liste:
[("Calibration hour", 3.0), 3.2, 3.3, 3.2, 3.0, 3.1, 3.5, 5.0, 5.0, 4.9, 4.0, 3.0, ("Calibration hour", 2.9), 2.2]
Eksempel 6: Finne feilene¶
Her er noen eksempler på ting som kan gå feil.
Last ned filen her: errors_1.py
. Før du kjør koden, se om du finner
alle feil som gjør at den ikke går å kjøre. Kjør siden koden. Fant du alle feil?
Endre koden så at den går å kjøre. Koderaden greeting_str =
str(full_greeting)
er ikke feil slik at man får en error fra Python, men den
gjør ikke akkurat hva vi vil at den skal gjøre. Endre så at det blir riktig
output.
a = [2, 4, 8, 9]
b = a
c = a
d = a[:]
a = a + [999, 777]
b += [111, 333]
c = c.append(55)
d.insert(len(d),77)
print(f'{a = }\n{b = }\n{c = }\n{d = }')
#############
some_list = [
4,
5
6,
7,
8,
]
# write a greeting string from a collection of letters
greeting_1 = ('H','e','l','l','o')
greeting_2 = ['t','h','e','r','e','!']
full_greeting = greeting_1 + ' ' + greeting_2
greeting_str = str(full_greeting)
print('Our result:', greeting_str)
print('Expected result:', 'Hello there!')
Oppgaver¶
Oppgave 1¶
Se Oppgave 1 rett nedenfor ekesempelen tupler.
Oppgave 2¶
Se Oppgave 2 rett nedenfor ekesempelen sekvenser.
Oppgave 3¶
Se Oppgave 3 rett nedenfor ekesempelen forandres vs ikke forandres.
Oppgave 4a¶
Se Oppgave 4a rett nedenfor ekesempelen zip()
.
Oppgave 4b¶
Se Oppgave 4b rett nedenfor ekesempelen zip()
.
Oppgave 5¶
Se Oppgave 5 rett nedenfor ekesempelen enumerate()
.
Oppgave 6¶
I filen uke_07_oppg_6.py
, skriv en funksjon som heter pigify()
og som
oversetter et ord fra engelsk til pig latin. Oversettelsen gjøres på følgende
måte:
Hvis et ord begynner med en vokal, skal funksjonen legge til -way på slutten av ordet (e.g., apple ↦ appleway). (I denne oppgaven regner vi ikke y som en vokal.)
Hvis ordet begynner med en konsonant, skal funksjonen flytte alle bokstavene i begynnelsen av ordet frem til den første vokalen, til slutten av ordet, og legge til -ay etter det (e.g., banana ↦ ananabay, string ↦ ingstray). (Hvis ordet bare inneholder konsonanter så skal kun -ay legges til på slutten av ordet.)
For eksempel, pigify("floor")
skal returnere:
"oorflay"
Skriv også en funksjon som heter pigify_sentence()
som tar en setning som
argument (som en string
) og som returnerer tilsvarende setning men ver hvert
ord er oversatt til pig latin. Du kan anta at alle setinger funksjonen blir kalt
med ikke inneholder spesialtegn eller store bokstaver. For eksempel,
pigify_sentence("alice was beginning to get very tired")
skal returnere:
"aliceway asway eginningbay otay etgay eryvay iredtay"
Oppgave 7¶
I filen uke_07_oppg_7.py
skal du lage en funksjon med navnet
render_plot()
som tar som argument en liste med koordinater (tupler med to
elementer) og som siden lager en streng som er en plot hvor det er plassert en
asterisk (*) på alle koordinatene i listen og mellomrom på alle de andre
koordinatene, og som har en ramme med «#» rundt hele plotten. Plotten skal være
så liten som mulig, det vil si, det skal ikke finnes med tomme rader eller
kolumner utenfor hvor alle punkter (*) er. For eksempel, render_plot([(2, 3),
(-1, 2), (1, -1), (0, 1)])
skal returnere følgende streng (hvor «⎵»
representerer mellomrom):
Hjørnet lengst ned til venstre innenfor rammen tilsvarer koordinaten (-1, -1)
(som ikke skal ha en asterisk), og hjørnet lengst opp til høyre innenfor
rammen tilsvarer koordinaten (2, 3) (som skal ha en asterisk). Om vi ville
brukt print()
til å skrive ut strengen på skjermen ville vi fått følgende
output:
######
# *#
#* #
# * #
# #
# * #
######
- Tips:
Det kan være en god idé å finne ut den høyeste og laveste x- og y-verdien. Om du har koordinatene i en liste som heter
coords
så kan du for eksempel skrivexs, ys = zip(*coords)
for å få alle x-verdiene i variabelenxs
og alle y-verdiene i variabelenys
. Skjønner du hvorfor dette gir x- og y-koordinatene? Det er også mulig å plukke ut x- og y-koordinatene på andre måter. Kanskje med en løkke?Når du vet den høyeste og laveste x- og y-verdien så kan du bruke
range()
(med én eller flere løkker?) til å iterere igjennom alle koordinatene i plotten og på hvert sted putte enten"*"
eller" "
. Hvilket python-konstrukt skal du bruke her for å bestemme om det skal være"*"
eller" "
?Du må også huske rammen rundt plotten. Vil du ta med rammen når du renderer plotten med alle koordinatene eller vil du først rendere plotten og siden legge til rammen etter det? Begge måtene er mulige.
Frivillig, ikke vurdert¶
Kan du også inkludere x-akselen som «—», og y-akselen som «|» i plotten? Så at
print(render_plot([(2, 3), (-1, 2), (1, -1), (0, 1)]))
ville gitt følgende
output:
######
# | *#
#*| #
# * #
#—|——#
# |* #
######