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 []
. Vi bruker vanligvis tupler for objekter hvor lengden ikke vil endres, dvs. antall objekter/elementer forventes å være statiske. 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 favorittleken
til en hund. Lag en funksjon kalt swap_tuple()
som tar som argument en tuple
med tre strenger. Den første strengen er hundens navn. Den andre strengen er
hundens personlighet. Den tredje strengen er favoritleken til hunden. Du skal bytte
ut favoritleken til "ball"
.
Eksempelkjøring:
>>> dog = ("Ollie", "joy", "squeaky toy")
>>> print(swap_tuple(dog))
("Ollie", "joy", "ball")
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:
"6.0 9.0 10.0 10.0 12.0 10.0 11.0" # 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 en tuple med temperaturene
konvertert til float
(i samme orden).
Eksempelkjøring:
>>> update_weather("6.0 9.0 10.0 10.0 12.0 10.0 11.0")
(6.0, 9.0, 10.0, 10.0, 12.0, 10.0, 11.0)
I uke_07_oppg_2.py
skriv også en funksjon som heter wednesday_weather()
og som tar en tuple med
en ukes temperaturer som float
og returnerer temperaturen på onsdag (også
som en float
).
Eksempelkjøring:
>>> wednesday_weather(6.0, 9.0, 10.0, 10.0, 12.0, 10.0, 11.0)
10.0
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 ovenfor 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 fredagens temperatur til 10.0
, og
returnerer det oppdaterte resultatet. Resultatet må være en tuple som
originallisten.
Eksempelkjøring:
>>> daily_temps = (('mandag', 6.0), ('tirsdag', 9.0), ('onsdag', 10.0), ('torsdag', 10.0), ('fredag', 12.0), ('lørdag', 10.0), ('søndag', 11.0))
>>> adjust_daily_temps(daily_temps)
(('mandag', 6.0), ('tirsdag', 9.0), ('onsdag', 10.0), ('torsdag', 10.0), ('fredag', 10.0), ('lørdag', 10.0), ('søndag', 11.0))
Eksempel 4a: 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 = list(zip(list1, list2)) # convert to list for multiple uses
for t in zip_list:
print(t)
# to revert a zip, you can use * (see the explanation in week 06)
reverted = list(zip(*zip_list))
print(reverted)
Eksempel 4b: Turtle¶
Vi kan demonstrere bruken av zip()
med turtle
eksemplet fra uke_06 med de to listene angles
og lengths
hvor zip()
er lett å bruke for å combinere disse to listene til én 2D list i format [(angle1, length1),(angle2, length2), ...]
. Vi kontrast denne metoden med en standard for loop-metode i koden nedenfor.
Last ned filen her: eksempel_4_turtle.py
, og kjør koden.
import turtle as t
# list of angles, list of lengths (same number of items!)
angles = [90.0, 90.0, 90.0, 90.0]
lengths = [100, 100, 100, 100]
# combine angles and lengths into 2D list according to index, f.eks. [[90.0,100], ... ]
angles_lengths = [] # create empty list for combined angles and lengths
# for-loop approach: loop over each item in the two lists and combine this way
for i in range(len(angles)):
angles_lengths.append([angles[i], lengths[i]])
print("Approach with for-loop")
print(angles_lengths) # now we have a 2D list of paired angles and lengths
# zip() approach: Much shorter/cleaner!
angles_lengths_zipped = list(
zip(angles, lengths)
) # alternatively, [*zip(angles, lengths)]
print("Approach with zip")
print(angles_lengths_zipped)
# we use either of these combined lists to give instructions to the turtle to draw a square:
for i in range(len(angles_lengths_zipped)):
t.left(angles_lengths_zipped[i][0])
t.forward(angles_lengths_zipped[i][1])
t.done()
Oppgave 4a¶
I denne oppgaven får vi gitt to tupler med navn, personlighet og favorittlek til
to hunder. I filen uke_07_oppg_4a.py
, skriv en funksjon som heter
tuple_repack()
og tar to tupler med hundinformasjon og returnerer en liste
med hudenes personligheter (i samme orden).
Eksempelkjøring:
>>> tuple_repack(("Ollie","joy","ball"), ("Iggy","nervous","squeaky toy"))
["joy", "nervous"]
Obs
TIPPS: 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 tuplen.
Eksempelkjøring:
>>> days_paired_temperatures = (("mandag", 10.0),("tirsdag", 9.0),("onsdag", 10.0),("torsdag", 9.5),("fredag", 11.5),("lørdag", 8.5),("søndag", 11.0))
>>> data_reorganize(days_paired_temperatures)
(('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'),
(10.0, 9.0, 10.0, 9.5, 11.5, 8.5, 11.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:
>>> wind_speed = [3.0, 4.0, 3.5, 5.5, 1.0, 0.3, 3.0, 4.5, 6.0, 11.0, 12.0, 1.0, 2.0, 2.0]
[('Calibration hour', 3.0), 4.0, 3.5, 5.5, 1.0, 0.3, 3.0, 4.5, 6.0, 11.0, 12.0, 1.0, ('Calibration hour', 2.0), 2.0]
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.
1a = [2, 4, 8, 9]
2b = a
3c = a
4d = a[:]
5
6a = a + [999, 777]
7
8b += [111, 333]
9
10c = c.append(55)
11
12d.insert(len(d),77)
13
14print(f'{a = }\n{b = }\n{c = }\n{d = }')
15
16#############
17
18some_list = [
194,
20 5
21 6,
22 7,
238,
24]
25
26# write a greeting string from a collection of letters
27
28greeting_1 = ('H','e','l','l','o')
29greeting_2 = ['t','h','e','r','e','!']
30
31full_greeting = greeting_1 + ' ' + greeting_2
32
33greeting_str = str(full_greeting)
34
35print('Our result:', greeting_str)
36print('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.)
Eksemplkjøring:
>>> pigify("door")
"oorday"
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.
Eksempelkjøring:
>>> pigify_sentence("time will not slow down when something unpleasant lies ahead"
"imetay illway otnay owslay ownday enwhay omethingsay unpleasantway ieslay aheadway"
Oppgave 7¶
Tilpasset fra The Python Workbook, Ex. 117:
En linje med best tilpasning er en rett linje som best tilnærmer en samling av \({n}\) datapunkter. Variablene \(\bar{x}\) og \(\bar{y}\) brukes å representere gjennomsnittsverdiene i samlingen. Linjen med best tilpasning er representert ved ligningen \(y = mx + b\) hvor \({m}\) og \({b}\) beregnes ved hjelp av følgende formler:
I filen uke_07_oppg_7.py
skal du lage en funksjon med navnet
line_best_fit()
som tar som argument en tuple av koordinater i tuple form ((x1, y1), (x2, y2), ...)
. Funksjonen skal returnere formelen for linjen med best tilpasning i formen \(y = mx + b\), hvor variablene \({m}\) og \({b}\) erstattes med verdiene du beregnet for formlene ovenfor for \({m}\) og \({b}\). Om verdien til \({b}\) er 0
, må formlene ikke inkludere \({b}\).
Eksempelkjøring:
>>> coord_1 = ((1, 1), (2, 2.1), (3, 2.9))
>>> line_best_fit(coord_1)
y = 0.95x + 0.1
>>> coord_2 = ((0, 0), (1, 1), (2, 2), (3, 3))
>>> line_best_fit(coord_2)
y = 1.0x
Obs
TIPPS: Du kan bruke zip()
for noen av beregningene for x og y for å løse for m og b, eller du kan bruke for-løkker. Før du begynner å prøve å kode, sørg for at du vet hva du trenger å beregne, og del problemet i mindre biter basert på hver av disse mindre verdiberegningene du må gjøre.