Uke 6 - Lister¶
Les https://automatetheboringstuff.com/2e/chapter4/ frem til «EXCEPTIONS TO INDENTATION RULES IN PYTHON»-boksen.
Eksempler¶
Denne uken skal vi se på noen eksempler på lister og hva man kan gjøre med dem.
Eksempel: Basics¶
Last ned filen her: eksempel_basic_lists.py
og kjør koden. Prøv å gjøre endringer i listene og se hva som skjer.
a = [5, 7, 2, 9, 10]
# You can use 'len()' with lists
print(a, len(a))
# You can use 'if _ in _:' with lists
if 9 in a:
print(f"9 is in the list a = {a}!")
b = [5, "str", 9.3]
print("Lists can have mixed types inside:", b)
c = a + b
print(f"We can concatenate lists: {c = }")
# You can extract values from a list
x, y, z = [1, 5, 7]
print(x)
print(y)
print(z)
Eksempel: Indeks¶
Hvert element i en liste har et tilsvarende indeks, dette tilsvarer elementets
posisjon i listen. Det første elementet har indeks 0, neste har indeks 1, etc.
Vi kan bruke indeks for å få ut/endre verdien på en viss posisjon i listen. Vi
kan bruke slice
-notasjon for å få ut en delliste.
Last ned filen her: eksempel_index.py
og kjør koden. Skjønner du hvordan indeks fungerer?
en_liste = ["a", "b", "c", "d", "e"]
print(f"{en_liste = }")
# Vi kommer åt verdien på indeks i ved å skrive en_liste[i].
print(f"{en_liste[0] = }")
print(f"{en_liste[1] = }")
# Siden indeks begynner på 0 så kommer det siste elementet ha indeks
# et mindre enn lengden av listen.
# print(en_liste[len(en_liste)]) # Dette gir en feilmelding.
print(f"{en_liste[4] = }")
# Indeks på siste elementet er alltid lengden av listen minus én.
print(f"{en_liste[len(en_liste) - 1] = }")
# Men vi kan også få det siste elementet ved å skrive kun [-1].
# Python subtraherer negative indeksverdier fra len() automatisk
print(f"{en_liste[-1] = }")
# Vi kan også endre verdiene i listen ved å bruke indeks.
print("Vi endrer listen ved å skrive: en_liste[2] = 'å'")
en_liste[2] = "å"
print(f"{en_liste = }")
# Vi kan få ut dellisten fra index i til og med j-1 ved å skrive [i:j].
print(f"{en_liste[1:4] = }")
# Vi kan dessuten hoppe over element.
print(f"{en_liste[0:5:2] = }") # en_liste[start:stop:step]
# Vi gå andre veien i listen.
print(f"{en_liste[3:1:-1] = }")
# Vi må ikke angi start og/eller stop om vi vil gå helt fra start og/eller helt til slutten.
print(f"{en_liste[:3] = }")
print(f"{en_liste[3::-1] = }")
print(f"{en_liste[:] = }")
# Vi kan også fjerne verdiene i listen ved å bruke del.
print("Vi endrer listen ved å skrive: del en_liste[3]")
del en_liste[3] # Tar bort elementet på indeks 3.
print(f"{en_liste = }") # en_liste er endret.
Obs
I Python kan vi bruke asterisk (*) for å pakke og utpakke flere verdier i lister. Dette er en litt mer avansert måte å bruke Python og du må ikke bruke det selv, men noen ganger kan det være veldig praktisk.
Last ned filen her: eksempel_asterisk.py
og prøv å kjøre koden.
# Du kan bruke * for å ekstrahere en delliste.
col_name, first, *rest = ["temp", 20.3, 21.0, 18.6, 18.2, 15.0, 12.5]
print(col_name)
print(first)
print(rest) # 'rest' er en liste
# Du kan bruke * i funksjonskall.
# Gitt en liste bruker vi * for å utpakke den til en sekvens av argumenter.
def add(a, b):
return a + b
xs = [4, 7]
print(add(*xs)) # det samme som print(add(4, 7))
# print(add(xs)) -> feil antall argumenter
print(*rest) # Ekvivalent med print(r_0,...,r_n) for alle elementer i 'rest'.
Eksempel: Lister av lister¶
Lister kan også inneholde andre lister. Da må vi bruke to tall for å indeksere
dem. Last ned eksempelet her eksempel_2D_lists.py
. Hva tror du den vil skrive ut? Var det riktig?
date_temp = [["2003-03-13", 9.8], ["2004-03-13", 10.2]]
print(f"The list date_temp: {date_temp}")
print(f"{date_temp[0] = }")
print(f"{date_temp[0][1] = }")
# Hva er date_temp[0][0]?
# Hva er date_temp[1][0]?
print()
numbers = [[1], [1, 2], [1, 2, 3]]
print(f"The list numbers: {numbers}")
print(f"{numbers[2] = }")
print(f"{numbers[2][1] = }")
# Hva skjer om du skriver numbers[1][2]?
print()
# Ulike muligheter til å printe en liste av lister
for row in numbers:
for n in row:
# Argumentet 'end' sier hva som skal printes aller sist. Default er "\n".
print(n, end=";")
print()
for row in numbers:
# Argumentet 'sep' sier hva som skal printes mellom argumentene. Default er " ".
print(*row, sep=" <> ")
Lister av lister kalles ofte 2-dimensjonale (2D) lister fordi du kan tenke på dem som et 2D koordinatsystem
grid = [["00", "01", "02"],
["10", "11", "12"],
["20", "21", "22"]]
print(grid[2][1]) # printer "21"
Eksempel: Listefunksjoner¶
Her er noen ulike metoder man kan bruke på lister. Du kan finne ut mer på https://docs.python.org/3/tutorial/datastructures.html#more-on-lists
Last ned filen her: eksempel_list_functions.py
og kjør koden. Skjønner du hva som skjer? Prøv
de ulike metodene selv.
# https://docs.python.org/3/tutorial/datastructures.html
a = [5, 7, 2, 9, 10]
print(f"a = {a}")
# .append()
a.append(7)
print(f"We append 7: {a}")
# .insert()
a.insert(2, 6)
print(f"We insert 6 at index 2: {a}")
# .reverse()
a.reverse()
print(f"We reverse a: {a}")
# .remove()
a.remove(7)
print(f"We remove the first occurence of 7: {a}")
# .sort()
a.sort()
print(f"We sort a: {a}")
Obs
Ingen av disse funksjonene har en returverdi. Alle endrer på listen direkte, slik at det er forskjell på listen før og etter at du brukt funksjonen.
Eksempel: Input i lister¶
I dette eksemplet spør vi brukeren om positive tall, og siden beregnes maksimum av tallene på to måter.
Last ned filen her: eksempel_input.py
og
kjør koden. Skjønner du hvordan while-løkken fungerer? Hvordan blir den
avsluttet? Hva gjør den siste raden i den løkken? Om du er usikker kan du gå
igjenom noen iterasjoner av løkken med papir og penn og se hva som skjer.
Skjønner du hvordan for-løkken fungerer?
# ask for several numbers
# store in list
# find maximum
def numbers_from_input():
"""Ask user for input to build a list of positive integers."""
nums = []
while True:
n = input("A positive number (q to stop): ")
if n == "q":
break
n = int(n)
if n < 0:
print("That was negative. Try again.")
continue
nums.append(n)
return nums
def my_max(nums):
"""Find the maximum of a list of numbers."""
maxnum = nums[0]
for num in nums[1:]:
if num > maxnum:
maxnum = num
return maxnum
nums = numbers_from_input()
print(f"You gave me {len(nums)} numbers.")
print("Your numbers are:", nums)
print("The maximum number is:", max(nums))
print("Doing max by hand...")
maxnum = my_max(nums)
print("My own max is:", maxnum)
I dette eksemplet lagrer vi tallene fra brukeren i en liste. Det er fordi vi ikke vet hvor mange tall vi kommer til å få fra brukeren. En liste i Python kan vi gjøre så lang som vi trenger. Vi må ikke vite på forhånd hvor lang den skal være.
Eksempel: Vanlige løkkestrukturer¶
Følgende er noen eksempler på en vanlig løkkestruktur når vi jobber med lister.
Last ned filen her: eksempel_common_loops.py
og kjør koden. Kommer du på flere problemer man
kan løse med denne strukturen?
def my_sum(numbers):
# Instansiere en variabel å bygge på.
summe = 0
# Kjør en for-løkke som bygger opp verdien i variabelen.
for number in numbers:
summe += number
return summe
# Beregner minimum av en liste med negative tall.
def my_min(numbers):
# Instansiere en variabel å bygge på.
minimum = numbers[0]
# Kjør en for-løkke som bygger opp verdien i variabelen.
for number in numbers:
if number < minimum:
minimum = number
return minimum
# Returnerer alle verdiene i 'xs' som er større enn 'lower_bound'.
def filter_greater_than(xs, lower_bound):
# Instansiere en variabel å bygge på.
filtered_list = []
# Kjør en for-løkke som bygger opp verdien i variabelen.
for number in xs:
if number > lower_bound:
filtered_list.append(number)
return filtered_list
# Konstruerer et histogram fra verdiene i 'values'.
def render_histogram(values):
# Instansiere en variabel å bygge på.
rows = []
# Kjør en for-løkke som bygger opp verdien i variabelen.
for value in values:
rows.append("*" * value)
return "\n".join(rows) # det neste eksempelet viser mer om .join()
print(my_sum([1, 2, 3, 4, 5]))
print(my_min([-1, -2, -8, -4, -5]))
print(filter_greater_than([1, 2, 3, 4, 5], 3))
print(render_histogram([1, 2, 3, 4, 5, 3, 8, 1]))
Eksempel: Strings og lister¶
Her er noen eksempler på metodene split()
og join()
som vi bruker for å konvertere
en streng i en liste av strenger og motsatt.
Last ned filen her: eksempel_strings.py
og
kjør koden. Hvordan fungerer split()
? Hvordan fungerer join()
? Hva gjør
for-løkken?
text = "Alice was beginning to get very tired"
print(text)
print("Default: splitting on whitespace")
words = text.split()
print(words)
print(len(words), "words")
print("Splitting on 't' instead:")
weird = text.split("t")
print(weird)
joined = "===".join(words)
print(joined)
nospaces = "".join(words)
print(nospaces)
print()
print("Lines of 3 words each:")
# Se til at du skjønner hva som skjer her!
line = []
for w in words:
if len(line) < 3:
line.append(w)
else:
print(" ".join(line))
line = [w] # Starte neste linje.
print(" ".join(line))
Eksempel: List Comprehension¶
Her er et eksempel på list comprehension (listeinklusjon). Det er en litt mer avansert syntaks og du må ikke bruke dette selv, men det kan være veldig praktisk ibland.
Listeinklusjon er en rask måte å lage nye lister fra verdiene til en eksisterende liste. Det er egentlig bare en annen måte å skrive en spesiell type for-løkke. Det går alltid å skrive om en listeinklusjon til en for-løkke. Sammenlign eksemplene nedenfor og forklar forskjellene til en venn.
animals = ["dog", "elephant", "bird"]
# Create new list with a for-loop.
lengths = []
for a in animals:
lengths.append(len(a))
print(lengths)
# Do the same thing using list comprehension.
lengths = [len(a) for a in animals]
print(lengths)
# Transforming a list into a new one in a for-loop.
xs = [-4, 1, 3, 7, 10, 12]
ys = []
for x in xs:
ys.append(x ** 2 - 2 * x + 1)
print(ys)
# Do the same thing using list comprehension.
ys = [x ** 2 - 2 * x + 1 for x in xs]
print(ys)
# We need to specify which is the variable we are looping over.
a = 5
multiples_of_a = [a * n for n in range(5)] # n is the variable we want to loop over.
print(multiples_of_a)
# We can also have an if-statement in a list comprehension.
squares_of_odds = [x ** 2 for x in range(20) if x % 2 == 1]
print(squares_of_odds)
Leseforståelse: Polynomer¶
I dette eksempelet lager vi en funksjon poly_string()
som gjør den samme
ting som funksjonen med samme navn i Eksempel 4, uke 5 men med
forskjellen at funksjonen tar en liste med koeffisienter som argument, sånn at
polynomet kan være av hvilken grad som helst.
Vi lager også en funksjon poly_val()
som beregner verdien av et polynom
i en punkt. Argumenten til funksjonen er en liste med koeffisienter og et tall.
Kan du forstå hva programmet gjør uten å kjøre det?
Last ned filen her: eksempel_poly.py
.
# Example of enumerate:
# printing polynomials,
# calculating values of polynomials
def poly_val(coeffs, x):
"""Calculate value of polynomial at a point
coeffs: a list of non-negative integer coefficients of a polynomial
sorted from lowest degree to highest degree
x: a float, the point at which to evaluate the polynomial
"""
sum = 0
for i, coe in enumerate(coeffs):
sum += coe * x ** i
return sum
def poly_string(coeffs):
"""Give a string representation of a polynomial
coeffs: a list of non-negative integer coefficients of a polynomial
sorted from lowest degree to highest degree
"""
terms = []
if coeffs: # Adding the constant term
coe = coeffs[0]
if coe != 0:
terms.append(str(coe))
coeffs = coeffs[1:]
if coeffs: # Adding the linear term
coe = coeffs[0]
if coe == 1:
terms.append("x")
elif coe > 1:
terms.append(f"{coe}x")
coeffs = coeffs[1:]
for i, coe in enumerate(coeffs): # Adding all other terms
if coe == 1:
terms.append(f"x^{i+2}")
elif coe > 1:
terms.append(f"{coe}x^{i+2}")
if not terms: # If we were given an empty list or only zeros
return "0"
else:
terms.reverse()
return " + ".join(terms)
# Give a list of coefficients sorted from highest to lowest degree
coeffs = [6, 12, 0, 1, 5] # 6x^4 + 12x^3 + x + 5
coeffs.reverse()
text = poly_string(coeffs)
x = 2
value = poly_val(coeffs, x)
print(f"The value of {text} at {x = } is {value}.")
Eksempel: in
¶
Her er et eksempel på bruk av in
med lister.
Last ned filen her: eksempel_in.py
. Før du kjører koden, hva tror du output blir? Kjør koden. Var det riktig?
# This code should tell a visitor entering a museum what
# they must pay, depending on whether the visitor is a
# senior, a student or none of the above. Try some different values.
def ticket_price(visitor_type):
"""Calculate the ticket price based on visitor category.
visitor_type: a list of categories
"""
if "senior" in visitor_type:
return 80
elif "student" in visitor_type:
return 90
else:
return 100
alice = ["Alice", "student", "senior"]
bob = ["Bob"]
carol = ["Carol", "senior"]
dan = ["Dan", "student"]
visitors = [alice, bob, carol, dan]
for v in visitors:
name = v[0]
price = ticket_price(v)
print(f"{name} has to pay kr.{price}.")
Eksempel: turtle¶
Her er et eksempel til bruk av lister med turtle. Vi tegner en spiral ut fra to lister, en med vinkler og en med lengder.
Vi bruker python-funksjonen exit()
et sted for å avslutte programmet om listene ikke har den samme lengden.
Last ned filen her: turtle_ex.py
.
import turtle as t
# list of angles, list of lengths
angles = [90.0, 90.0, 90.0, 90.0, 90.0]
lengths = [100, 120, 150, 180, 300]
# loop over each item in the two lists
if len(angles) != len(lengths): # why have this here?
print("lists not same length")
exit() # stops the program
# we use this combined list to give instructions to the turtle to draw a square:
for i in range(len(angles)):
t.left(angles[i])
t.forward(lengths[i])
t.done()
Eksempel: Feil¶
Her er et eksempel på ting som kan gå galt med lister.
Last ned filen her: eks/errors_1.py
. Før du kjør koden, se om du finner alle feil.
Prøv å kjøre koden. Endre sånn at koden går å kjøre.
1a = ["xyz", "abc", 5.4, "z", True, 7, "Hei there"]
2length = len(a)
3print(a[length])
4
5
6b = [12, 34, 1, 107, "14", 16, 19]
7b.sort()
8print(b)
9
10#####
11
12print("Returning coins:")
13
14coins = [1, 5, 10, 20]
15
16price = 24
17payment = 50
18
19# work out return coins
20diff = payment - price
21for c in coins:
22 while diff > c:
23 print(f"Returning kr.{c}")
24 diff -= c
Koden i slutten skal beregne vekslepenger som skal returneres ved en betaling. Det finnes 20-kr, 10-kr, 5-kr og 1-kr. Den skal returnere slik at man får så få mynter som mulig. For eksempel, om prisen er 24 kr og betalingen er 50 kr skal den returnere én 20-kr, én 5-kr og én 1-kr. Men noe er feil med koden sånn at den ikke gjør helt som den skal. Kan du endre sånn at den fungerer som den skal?
Ekstra øving:¶
For å sjekke hva du har lært kan du gjøre ’practice questions’ 1-10 i kapittel 4 i Automate the Boring Stuff.
Oppgaver¶
Obs
Alle oppgavene er obligatoriske denne uken!
Oppgave 1¶
I filen uke_o6_oppg_1.py
skal du definere følgende funksjoner:
remove_fives()
: tar en liste og returnerer samme liste men med alle forekomster av tallet \(5\) fjernet.Eksempelkjøring:
>>> remove_fives([0, 5, 95, 25, 50, 7, 20, 11]) [0, 95, 25, 50, 7, 20, 11]
every_third()
: tar en liste og returnerer en liste med kun hvert tredje element.Eksempelkjøring:
>>> every_third(['a', 1, 'b', 'c', 2, 6, 'g', 4, 'p', 'q']) ['a', 'c', 'g', 'q']
Obs
TIPPS: bruk
slice
-notasjonreverse()
: tar en liste og snur rekkefølgen på den.Eksempelkjøring:
>>> reverse([5, 6, 7, 8, 9, 10]) [10, 9, 8, 7, 6, 5]
halve_values()
: tar en liste med tall og returnerer listen hvor alle tallene i listen halveres.Eksempelkjøring:
>>> halve_values([1, 2, 3, 4]) [0.5, 1.0, 1.5, 2.0]
Obs
TIPPS: bruk
append()
eller list comprehension.unique_values()
: tar en liste og returnerer en liste hvor alle multiple forekomster av verdiene er fjernet (i den rekkefølge verdiene først dukker opp).Eksempelkjøring:
>>> unique_values([3, 1, 6, 10, 30, 30, 30, 3, 0, 6]) [3, 1, 6, 10, 30, 0]
Obs
TIPPS: Du kan enten lage en ny liste med
append()
eller så kan du brukeremove()
med den opprinnelige listen.Skriv din egen versjon av den innbygde funksjonen len, med navnet
my_len()
. Den skal returnere lengden av en liste eller en streng, slik som len. Du kan ikke kalle på andre funksjoner inne imy_len()
.Eksempelkjøring:
>>> my_len([]) 0 >>> my_len("123") 3
Oppgave 2¶
Gitt en liste med koordinater i formen (x,y)
, i filen uke_06_oppg_2.py
skriv funksjonen find_highest()
som ta som input 2D-listen og går gjennom listen for å returnere indeksen som inneholder den høyeste verdien for y
.
Eksempelkjøring:
>>> find_highest([[96, 33], [20, 96], [30, 69], [59, 9], [22, 93]]) 1
Oppgave 3¶
En DNA-sekvens (f.eks ATAGCAGT
) sammensettes av 4 ulike «baser»,
som beskrives med A
, T
, G
og C
.
Under replikasjon av sekvensen kan hver base settes sammen med
eksakt én av de andre. A
med T
, og C
med G
original ------->
ATAGCAGT
||||||||
TATCGTCA
<------- complement
Slik får man en «komplementstreng» av den opprinnelige DNA-sekvensen.
Det vanlig å skrive ned komplementstrenger baklengs, slik at i vårt eksempel
sier vi at komplementstrengen til ATAGCAGT
er ACTGCTAT
(ikke
TATCGTCA
).
I filen uke_06_oppg_3.py
lag en funksion som heter complement()
og som
returnerer komplementstrengen av en DNA-sekvens. Funksjonen skal ta inn én
streng som argument, og skal returnere én streng. Du kan anta at alle
input-strenger er gyldige DNA-sekvenser.
Oppgave 4¶
I filen uke_06_oppg_4.py
skal du lage en funksjon som heter
render_histogram()
som tar en liste med positive heltall og returnerer et
histogram som bruker stapler av "*"
for verdiene i listen. For eksempel,
print(render_histogram([5, 4, 2, 7, 0, 3, 10]))
skal gi følgende output:
*
*
*
* *
* *
* * *
** * *
** * **
**** **
**** **
Obs
TIPPS: Du kan starte med versjonen av render_histogram
som finnes i eksemplene ovenfor.
Pytest-filer¶
Pytest-filene vi bruker på Codegrade: uke_06_tests.zip