Uke 7 — list / tuple / functions

Denne uken avslutter vi med lister, tuple og funksjoner. Les https://automatetheboringstuff.com/2e/chapter4/ frem til «A Short Program: Conway’s Game of Life» og avsnittet «Keyword Arguments and the print() Function» i https://automatetheboringstuff.com/2e/chapter3/

Eksempler

Eksempel: 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_tuple.py, og kjør koden.

# a tuple with three elements
a = (1,'b',3)

# a tuple with one element (notice the comma)
b = (1,)

print("Two tuples:")
print(f"a = {a}\nb = {b}\n")

print("Tuple unpacking:")

x, y, z = a
print(f"x = {x}\ny = {y}\nz = {z}\n")

print("Lists of tuples:")
# here is a list of tuples
list_of_tuples = [(7, 'a'), (12, 'x'), (3, 'B')]

# we can unpack them automatically while going through the list
for first, second in list_of_tuples:
    print("Number", first, "belongs to", second)

Eksempel: Sekvenser

Her er noen eksempler på lister, tupler og strenger. De er like på mange måter, hovedforskjellen er at listene kan endres, vi kaller det for «mutable». Tuples, strenger og de enkle datatypene int, float, bool er «immutable», og kan kun endres ved å lage en ny kopi av verdien.

Last ned filen her: eksempel_sequence_types.py, og kjør koden. Skjønner du hva som skjer?

# sequence types: list, tuple, str

# list - mutable, can be modified
x = [2,3,5,6,7] # list type
x[2] = 999
print(x)
x = x + [3,4]
print(x)


# tuple - immutable, cannot be modified
y = (2,3,5,6,7) # tuple type
#y[2] = 999 is an error
print(y)
y = y + (3,4)
print(y)

# string - immutable, cannot be modified
z = "23567"
#z[2] = "9" is an error
print(z)
z = z + "9876"
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))

print('\n'*3)

Eksempel: Forandres vs ikke forandres

Her er noen eksempler på forskjellen mellom lister, som er ’mutable’ (kan forandres), og tupler, som er ’immutable’ (kan ikke forandres).

Last ned filen her: eksempel_mutable.py, og kjør koden. Skjønner du hva som skjer? Hvorfor er b blitt endret etter a += [999, 777]? Hvorfor er b ikke blitt 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: map()

map() tar a funksjon og en liste og bruker funksjonen på hvert element i listen. map(f, [a, b, c]) blir [f(a), f(b), f(c)]. Det kan være fint hvis du vil gjøre det samme for alle elementene i listen, men fortsatt ha en liste.

Last ned filen her: eksempel_map.py, og kjør koden.

# example of map()

def double(x):
    return 2*x

my_list = [1,2,3,4]

dbl_list = map(double, my_list)

for num in dbl_list:
    print(num)


list_of_words = ["te", "kaffe", "appelsinjuice"]

max_length = max(map(len, list_of_words))
print(max_length)

Eksempel: 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. Den 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 på zip() outputet.

Last ned filen her: eksempel_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)

Eksempel: Funksjoner

Her er noen eksempler på funksjoner med ’keyword arguments’.

Last ned filen her: eksempel_func.py, og kjør koden. Skjønner du hva som skjer?

def func(a, b, c=5, d=7, e=9):
    return a + b * c - d + e


def func_2(x=5, y=7):
    return x + y


print("Testing function calls:")
print("func")
print(func(2, 3))
print(func(5, 7, d=9))
print(func(10, 12, 101, 999))
print(func(56, 22, e=102, c=567))

print("func_2")
print(func_2())
print(func_2(9))
print(func_2(x=77))
print(func_2(y=77))
print(func_2(10, 12))
print(func_2(x=123, y=987))

print("\n" * 3)

############################
# some builtin functions have options

print("Hello", "bye", 5, 7, sep="....")
print("Hello", "bye", 5, 7, sep="")

print("How are you", end="... ")
print("still here?")

print("This is the usual setting:", 5, 7, 9, "hi", sep=" ", end="\n")
# try other sep and end values ^^^
print("still here!")

############################


def my_sum(a, b, c, debug=False):
    if debug:
        print("inside my_sum:", a, b, c)
    return a + b + c


x = my_sum(3, 4, 5)
print("The sum is", x)

y = my_sum(1.2, 4, 5.6, True)
print("The sum is", y)

z = my_sum("a", "bb", "ccc", debug=True)
print("The sum is", z)

Se på de tre siste funksjonskallene. Her brukes funksjonen my_sum på tre forskjellige måter. Hvordan er resultatet forskjellig? Kan du forklare hvorfor?

Eksempel: 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!')

Spørsmål

Oppgaver

Oppgave 1

I oppgave_1.py fra listen names, bruk listeinklusjon for å bygge en ny liste som inneholder en liste til for hvert navn, med (1) navnet stavet baklengs, og (2) lengden på navnet.

Skriv ut resultatet.

names = ['Jakob', 'Emma', 'Ola', 'Sondre', 'Maia', 'Emilie', 'Noa']

Hvis du trenger å friske opp hukommelsen på listeinklusjon kan du se på forrige ukes oppgaver.

Eksempelkjøring (for listen ['Bob','Oliver']):

[['boB', 3], ['revilO', 6]]

Oppgave 2

I oppgave_2.py gjør det samme som i oppgave 1, med denne gangen bruk map() metoden. Du må definere en funksjon som kan brukes i map().

Husk: i python 3 må den returnerte verdien fra map() konverteres til list() for å returnere en liste.

Oppgave 3

I oppgave_3.py pakk ut tuplene cat og dog til verdiene personlighet, stemme, favorittmat. Lag en ny liste som inneholder personligheten til begge to. Du kan bruke zip() og hente ut det første elementet.

cat = ('aloof', 'meow', 'tuna')

dog = ('friendly', 'woof', 'sausage')

Eksempelkjøring:

['aloof', 'friendly']

Oppgave 4

I oppgave_4.py bytt ut kattens favorittmat fra tuna til laks. Skriv ut den nye tuplen.

cat = ('aloof', 'meow', 'tuna')

Oppgave 5

Vi kan også tenke på lister som stacks. I oppgave_5.py bruk append() og pop() metoder for å legge til tallene 6 og 7 til stack og for ta ut det siste tre tallene fra stack. Skriv ut resultatet i den rekkefølgen du får fra pop().

stack = [3, 4, 5]

Oppgave 6 - Pig latin

I oppgave_6.py bruk input() i en løkke for å bygge en liste med minst 3 ord (alle små bokstaver) fra bruker-input. Avbryt løkken når brukeren ikke skriver noe.

Lag en funksjon som heter pigify som gjør følgende:

  1. hvis et ord begynner med en vokal, legger -way til slutten av ordet

    (e.g., eple –> epleway)

  2. hvis ordet ikke begynner med en vokal, skal funksjonen flytte alle bokstavene i begynnelsen av ordet frem til den første vokalen til slutten av ordet, og legge til -ay (e.g., banan –> ananbay, plomme -> ommeplay). Kjør funksjonen på listen din og skriv ut resultatet.

Eksempelkjøring:

Enter word: dog
Enter word: shrew
Enter word: orange
Enter word:

original words:
['dog', 'shrew', 'orange']

words in pig latin:
['ogday', 'ewshray', 'orangeway']

Hint: Du kan bruke map() metoden for å bruke pigify funksjonen på hvert ord i listen din.

Oppgave 7

I oppgave_7.py bruk sorted() med søkeordargumenter for å sortere listen frukt etter ordlengde. (https://docs.python.org/3.9/library/functions.html#sorted)

frukt = ['eple', 'appelsin', 'ananas', 'kokosnøtt', 'banan', 'kirsebær']

Oppgave 8

I oppgave_8.py skal vi lage en funksjon som regner ut vekslepenger. Skriv en funksjon return_change(payment, price) som returnerer en liste med mynter som skal betales tilbake. Myntene er 1, 5, 10 og 20-kroner, og vi vil betale tilbake med så få mynter som mulig. (vi vil heller bruk én 20-kroning enn tjue 1-kroninger). Ikke bruke print() eller input() i innleveringen.

Eksempelkjøring:

>>> return_change(30, 20)
[10]
>>> return_change(30, 13)
[10, 5, 1, 1]

Tips: se på eksemplene fra forrige uke!