Prøveeksamen

8. november 2024
4 timer
Lukket digital eksamen (med safe exam browser).
Tillatte hjelpemiddel: bøker frå litteraturlista og opp til 6 tosidige A4 ark med eigne notat.
 

I tillegg til å være en mulighet for studenter å prøve ut en eksamen-setting, var prøveeksamen dette semesteret også delvis utviklet for forskningsformål. Oppgaveforfatterne har blitt inspirert av tidligere eksamener i emnet og har fått noen inspill fra emneansvarlig før utviklingen av prøven. Noen av oppgavene kommer også fra tidligere eksamener i emnet. Noen av oppgavene i de tre variantene av prøveeksamen var skrevet med ulike bakgrunnshistorier, men løsningene på problemene var i stor grad identisk.

Oppgavetekster, løsningsforslag og sensorveiledning finner du på denne siden.

  1. Automatisk rettet
  2. Forklaring
  3. Kodeskriving

Fordi eksamen var en lukket digital eksamen uten tilgang til å kjøre koden eller bruke internett, bes sensor ikke gi poengtrekk for forhold som enkelt ville blitt oppdaget og raskt rettet ved kjøring av koden. Dette inkluderer blant annet:

  • manglende import-setninger,
  • manglende kodeord (som f. eks. manglende def foran funksjonsdefinisjoner),
  • feil navn på funksjoner og metoder i standardbiblioteket, i egen kode eller i eksterne moduler (såfremt det fremgår noenlunde av funksjonsnavnet hva kandidaten egentlig mener),
  • feil navn på variabler (f. eks. kalle den samme variabelen både total og sum i ulike deler av koden),
  • enkle syntaks-feil (f. eks. manglende kolon etter if-setninger),
  • og så videre.

Logiske feil skal det likevel (som hovedregel) bli trukket litt for; selv om man kunne ha oppdaget at noe var feil ved kjøring av koden. Dette inkluderer blant annet:

  • presedensfeil,

  • forveksling av indekser og elementer,

  • off-by-one -feil,

  • feil i algoritmer,

  • og så videre.

Under selve prøveeksamen (se pdf’ene over) var det noen småfeil og uklarheter i noen av oppgavetekstene. På denne siden har jeg (Torstein) forsøkt å rette opp det jeg ikke skjønte helt med oppgavene, slik at siden blir mer anvendelig som en ressurs å øve med.


1 Automatisk rettet

buttons = 0
smartphone = {
  0: 'battery',
  'camera': {
    'front': 1,
    'back': 4 },
  (2, 4): 'camera',
  'buttons': 2,
}

# Anta at kodesnutten over har blitt kjørt.
# Hva skrives ut i disse setningene? 
# Dersom programmet ville krasjet på linjen, skriv kun Error.

print("buttons")
print(smartphone[(2, 4)])
print(type(smartphone['camera']))
print(len(smartphone))
print(smartphone[(2, 4)] in smartphone)
print(smartphone[buttons])

For å se fasit, klikk «kjør».

a = 96
b = 'UiB'
c = {3, 5, 2}
d = -4.5
e = [60, 'Bergen', 5]

Anta at kodesnutten over er kjørt. Hvilken datatype har verdien disse uttrykkene evaluerer til? Dersom du mener evaluering av uttrykket krasjer, velg Error.

a * d
[c]
e + a
'UiB' in e
c[2]
e[1][e[2]]
a / a
a + a
len(c)
a * b

Klikk på de grå feltene for å se svaret.

def foo(x): 
    x += 2
    return x
    
x = 10
y = foo(x)
print(x + y)

Hva skriver dette programmet ut (hvis programmet krasjer, skriv kun Error)?

For å se fasit, klikk «kjør».

def check_first_bottle_open(bottle_status):
    first_bottle = bottle_status[0]
    if first_bottle == 0:
        return False
    for bottle in bottle_status[1:]:
        if bottle == 1:
            return False
    return True
    
print(not check_first_bottle_open([1, 0, 0, 1, 0]))

Hva skriver dette programmet ut (hvis programmet krasjer, skriv kun Error)?

For å se fasit, klikk «kjør».

def qiz(x, a):
    for e in a:
        if x % 2 == 0:
            x += e
    return x

q = [2, 4, 5, 6]
print(qiz(0, q))

Hva skriver dette programmet ut (hvis programmet krasjer, skriv kun Error)?

For å se fasit, klikk «kjør».

def wut(x):
    if x[0] == 'a':
        if 'c' in x[2]:
            if x[1] == 5:
                return True
            elif x[1] != 10:
                y = str(x[1])
                return 'y'
            else:
                if len(x) == 3:
                    y = x[1] + x[2]
                    return y
                else:
                    return x[1]
                    
print(wut(['a', '123', 'bc']))

Hva skriver dette programmet ut (hvis programmet krasjer, skriv kun Error)?

For å se fasit, klikk «kjør».

Gitt verdiene for a, b og c, hva evaluerer uttrykkene til?

a b c a or (b and c) a or (not b)
True False False
True False True
False True True
False False True

Klikk på de grå feltene for å se svaret.

Hvordan plassere parenteser for å få et uttrykk identisk med

 a or b and y < z or c

((a) or (b)) and y < (z or c)
a or (b and (y < (z or c)))
(((a or b) and y) < z) or c
a or (b and ((y < z) or c))
((a or b) and (y < z)) or c
(a or (b and (y < z))) or c

Klikk på det grå feltet i linjen du tror er riktig for å se om du valgte rett.

Hva evaluerer uttrykkene til? Dersom du mener uttrykket vil krasje, skriv «Error».

set('hello') == {'e','l','o','o','h','h','h'}
len([1, 2, 3] * 49) % 7 != 0
len([[[[['oops']]]]]) == 1
True < False
[1].extend([2]) == [1].append(2)
len({2: 42}.values()) < len({3: 43}.items())
'pony' in 'toponymy'
99 < 1e2 < 101

Klikk på de grå feltene for å se svaret.

Hva evaluerer uttrykkene til? Dersom du mener uttrykket vil krasje, skriv «Error».

set([number + 1 for number in [0,1,1,2,3,5]])
''.join([let*2 for let in 'hurra'])
[float(x) for x in '382475' if int(x) % 2 == 0]
'lykke til'[::-1]

Klikk på de grå feltene for å se svaret.

2 Forklaring
(2.1)  Tidemann's snake (10 poeng)

Tidemann held på med lab5 (Snake), men har gjort noko feil i steget der han skal teikna eit rutenett. Når test-programmet hans view_test.py køyrer, blir programmet til venstre vist, sjølv om han eigentleg skulle ønske at det såg ut som programmet til høgre. Det kjem ingen feilmeldingar i terminalen.

Tidemann sitt program Ønsket program

Kva har Tidemann gjort feil? Les koden hans, og forklar:

  • kva han har gjort feil,
  • kvifor feilen fører til åtferda som blir vist, og
  • kva han kan gjera for å retta feila.

Maks 400 ord.

Tidemann har gjort flere feil:

  1. I snake_view.py på linje 11 i funksjonen draw_board er det oppgitt at løkken skal gå gjennom elementene i range(rows). Dette fører til at det blir tegnet for få kolonner i rutenettet. For å rette feilen, endre linje 11 slik at løkken går igjennom elementene i range(cols) i stedet.

  2. I snake_view.py, på linje 32-33 i funksjonen get_color angis det at fargen skal være oransje dersom den innkommende verdien er større enn eller lik 0. Dette fører til at funksjonen vil returnere fargen oransje selv om verdien er 0, som ikke er riktig oppførsel, og vi ser på bildet at hele brettet tegnes i den oransje fargen, også der det skulle vært grå. Dette problemet kan løses på (minst) tre ulike måter, og ideelt sett burde man gjøre alle disse rettelsene (selv om hvert enkelt grep i seg selv er egentlig er tilstrekkelig for rette funksjonaliteten):

    • I stedet for å sammenligne med >=, burde man sammenlignet med >. Da ville ikke kroppen til denne if-setningen bli utført, og det er istedet den lysegrå fargen som blir angitt til color-variabelen tidligere i funksjonen (linje 30-31) som gjør seg gjeldende.
    • I stedet for å angi verdi til en variabel color som returneres på slutten av funksjonen, kunne man returnert verdier direkte inne i if-blokkene. Da ville funksjonen returnert allerede i den første if-blokken.
    • I stedet for å benytte flere if-setninger, burde man benyttet seg av én if-setning med flere elif-ledd; altså endre if på linje 32 til elif. Da ville color-variabelen blitt angitt kun i det første leddet av if-elif-sekvensen.
  1. I snake_view.py, på linje 22-26 i funksjonen draw_board tegnes debug-informasjon for en celle i en if-setning; men denne if-setningen har et innrykk for lite, og utføres derfor kun én gang for hver rad, etter at den innerste løkken er ferdig utført. Variablene x_left, x_right, y_top og y_bottom vil fortsatt ha de verdiene de fikk i siste iterasjon av den innerste løkken, som er ansvarlig for å tegne siste kolonne i raden. Derfor tegnes debug-informasjonen kun for den siste kolonne. For å rette koden, må innrykket på linjene 22-26 økes med ett innrykk (fire mellomrom).
  • For få kolonner (2 poeng)
    • Identifiserer at dette er et problem.
    • Foreslår funksjonell løsning for hva som kan gjøres for å rette problemet.
  • For mye oransje (2 poeng)
    • Identifiserer at dette er et problem.
    • Foreslår funksjonell løsning for hva som kan gjøres for å rette problemet.
  • Debug vises kun for siste kolonne (2 poeng)
    • Identifiserer at dette er et problem.
    • Foreslår funksjonell løsning for hva som kan gjøres for å rette problemet.
  • Helhetsvurdering (4 poeng)
    • Meningsfulle forklaringer av sammenheng mellom kode og resultatbilde.
    • Gode bruk av faguttrykk.
    • Finner ikke feil som ikke er feil.
(2.2)  Tell «s» (10 poeng)
def count_s(string):
    for c in range(len(string)):
        count = 0
        if c == 's': 
            count += 1
        return count 

Spillet «Stein, saks, papir» har et unikt navn i mange land i verden: kai-bai-bo i Korea, eller ching chong cha i Sør-Afrika.

Vi skrev funksjonen ovenfor for å telle hvor mange av bokstaven 's' det er i strengen som inneholder en oversettelese av «stein, saks, papir» fra et eller annet sted rundt om i verden. Av en eller annen grunn virker den ikke som den skal.

Klimatilpasningsstrategier er tiltak som hjelper menneskelige og naturlige systemer med å tilpasse seg klimaendringene.

Maya skrev funksjonen ovenfor for å telle hvor mange av bokstaven 's' det er i strengen som inneholder ulike tilpasningsstrategier. Av en eller annen grunn virker den ikke som den skal.

Eliteserien er en norsk toppserie i fotball, og 17 forskjelige klubber har vunnet den minst én gang.

Lucas skrev funksjonen ovenfor for å telle hvor mange av bokstaven 's' det er i en streng som beskriver et lag fra Eliteserien. Av en eller annen grunn virker den ikke som den skal.

Forklar:

  • Hva er galt?
  • Hvordan kan du korrigere programmet slik at det fungerer? Forklar nøyaktig hvor og hvordan du har tenkt å gjøre korrigeringen.

Omtrent to til tre avsnitt, helst ikke mer enn 200 ord.

Koden har flere feil.

  • Løkken blander indekser med tegn i strengen. Løkken er over indekser (den bruker range(len(...))), men iteranden c blir brukt som om den er et symbol i strengen (f. eks. c == "a"). For å reparerer dette, må vi endre for c in range(len(s)): til for c in s:.

  • count blir satt til 0 på nytt hver gang blokken i løkken kjører. Dette er fordi count blir definert inni løkken. For å reparerer dette, må vi flytte count = 0 utenfor løkken (før løkken starter).

  • return count blir kjørt allerede etter første gjennomgang av løkken, og kodeblokken i løkken utføres derfor bare én gang. Når return -setningen utføres inne i en løkke, avbrytes løkken og funksjonskallet med én gang. For å reparerer dette, må vi endre innrykket og flytte return count utenfor løkken (etter at løkken er ferdig).

Reparert versjon (løsning trenger ikke inkludere dette for å få full pott):

def count_a(s):
    count = 0
    for c in s:
        if c == "a":
            count += 1
    return count

print(count_a("banan"))
  • 3 poeng: count = 0 må flyttes utenfor løkken.
  • 2 poeng: Løkken blander sammen indekser og elementer i strengen.
  • 3 poeng: For tidlig return
  • 2 poeng: Skjønnsmessig vurdering. Bruker kandidaten gode faguttrykk? Er det sammenheng mellom resonnementer?
(2.3)  Othilie's muterbare oppslagsverk (10 poeng)

Othilie har lese seg opp om oppslagsverk, og har lagt merke til at dei er muterbare. Men kva innberar eigentleg det? Kva omsyn må Othilie ta med muterbare objekter, som kanskje ikkje ville vore nødvendig elles?

Gi ei forklaring til Othilie med illustrerande døme, kor døme er basert på oppslagsverk. Me forventar ca 3-4 avsnitt, ikkje meir enn 600 ord.

En verdi er muterbar hvis det er mulig å endre på selve verdien i minnet etter at den har blitt opprettet første gang. Når Othilie arbeider med muterbare verdier, må hun være oppmerksom på at endringer i verdien vil påvirke alle referanser (aliaser) til den verdien. Dette kan føre til uventede bugs hvis én del av kildekoden tror det er greit å mutere verdien, mens en annen del av kildekoden ikke er klar over at verdien muteres.

Et eksempel: anta at Othilie har et oppslagsverk som inneholder karakterkortet hennes:

othilie_grades = {'Skriving': 5, 'Lesing': 4 }

Othilie lurer på hva snittkarakteren hennes blir hvis hun får karakteren x i sitt neste fag. Hun skriver derfor følgende funksjon:

def ave_if_adding_grade_x(grades, x):
    grades['new_grade'] = x
    # OBS! operasjonen over muterer grades!
    # men det er i det minste lett å regne ut gjennomsnittet nå:
    return sum(grades.values()) / len(grades) 

Når Othilie tester funksjonen, ser det ut som den fungerer som den skal:

print('Testing ave_if_adding_grade_x...', end=' ')
assert 5.0 == ave_if_adding_grade_x(othilie_grades, 6)
assert 4.0 == ave_if_adding_grade_x(othilie_grades, 3)
print('OK') # Tjohei, testene passerer!

Men når Othilie nå ser på karakterkortet sitt, ser hun at det har skjedd noe rart:

print(othilie_grades)

Gir utskriften

{'Skriving': 5, 'Lesing': 4, 'new_grade': 3}

Det som har skjedd, er at funksjonen ave_if_adding_grade_x muterer grades slik at det blir enklere å deretter regne ut gjennomsnittet. Det man ikke tenkte på, var at grades i ave_if_adding_grade_x er et alias til othilie_grades i hovedprogrammet, slik at enhver mutasjon av grades også vil reflekteres i othilie_grades.

Generelt når man benytter seg av verdier som er av en muterbar type, må man være bevisst på hvorvidt det finnes andre referanser/aliaser til verdien og hvilken rolle den spiller der før man bestemmer seg for å mutere den.

  • 2 poeng: meningsfull definisjon («En verdi er muterbar dersom selve objektet kan endres uten å opprette en ny verdi i minnet») eller lignende.
  • 2 poeng: meningsfullt svar på hvilke hensyn man må ta («Man må være bevisst på hvorvidt det finnes andre referanser/aliaser til en verdi før man bestemmer seg for å mutere den») eller lignende.
  • 2 poeng: eksempel basert på oppslagsverk, ikke kun lister.
  • 2 poeng: meningsfull drøfting av aliaser/to variabler som peker til samme objekt, eventuelt et godt eksempel som illustrerer dette.
  • 2 poeng: helhetsvurdering (bruk av fagbegreper, påstander gir mening, forståelse er korrekt etc).

3 Kodeskriving
(3.1)  Lister i minnet (4 poeng)
Illustrasjon av variabler og minnets tilstand slik det skal gjenskapes

Skriv en kodesnutt slik at minnets tilstand blir som vist over. Du vil ikke få trekk i poeng dersom du definerer andre variabler i tilegg.

Klikk på «se steg» -knappen for å verifisere at denne koden gir riktig bilde av minnet.

a = [[1, 2, 3], [1, 2, 3]]
b = [[1, 2, 3]] * 2

temp1 = [1, 2, 3]
temp2 = [1, 2, 3]
temp3 = [1, 2, 3]

a = [temp1, temp2]
b = [temp3, temp3]
a = [[1, 2, 3], [1, 2, 3]]
b = [[1, 2, 3]]
b.append(b[0])
a = []
a.append([1, 2, 3])
a.append([1, 2, 3])

b = []
b.append([1, 2, 3])
b.append(b[0])

  • 1 poeng hvis a er korrekt (a == [[1, 2, 3], [1, 2, 3]]).
  • 1 poeng hvis b er korrekt (b == [[1, 2, 3], [1, 2, 3]]).
  • 1 poeng hvis b[0] og b[1] viser til samme objekt (b[0] is b[1]).
  • 1 poeng hvis a[0] og a[1] er like, men viser til ulike objekter (a[0] == a[1] and a[0] is not a[1]).
  • 1 poeng hvis ingen av elementene i b viser til et element i a (b[0] is not a[0] and b[0] is not a[1] and b[1] is not a[0] and b[1] is not a[1]), selv om alle elementene i a og b er like.

Sensor har anledning til å gjøre en skjønnsmessig justering i tilfeller der det er gjort feil disse testene ikke tar høyde for. Poengsummen som beskrevet over kan regnes ut med følgende kode:

points = sum([
    a == [[1, 2, 3], [1, 2, 3]],
    b == [[1, 2, 3], [1, 2, 3]],
    b[0] is b[1],
    (a[0] == a[1]) and (a[0] is not a[1]),
    (
          ((b[0] is not a[0]) and (b[0] == a[0])) 
      and ((b[0] is not a[1]) and (b[0] == a[1]))
      and ((b[1] is not a[0]) and (b[1] == a[0]))
      and ((b[1] is not a[1]) and (b[1] == a[1]))
    )
])
# PS: i kontekst av matematisk aritmetikk regnes True som 1 og False som 0.
(3.2)  Telle ting (13 poeng)

fruits = {
    'QuickBuy': [
        '*Apple*, Orange, Banana',
        'Apple, *Orange*, Kiwi',
        'Apple, Orange, *Banana*, Peach, Kiwi',
        'Apple, *Orange*, Peach',
        '*Ananas*'
    ],
    '24/7 Grocery Store': [
        'Orange, *Banana*, Mango',
        'Apple, *Banana*, Mango',
        '*Banana*',
        '*Apple*, Apple, Peach, Kiwi, Mango, Guava',
        '*Ananas*'
    ],
    'Exotic Citrus': [
        'Avocado, *Mango*',
        '*Apple*, Banana, Mango, Papaya',
        '*Kiwi*',
        'Apple, Peach, Kiwi, Mango, Guava, *Papaya*',
        '*Ananas*'
    ]
}

Anta at fruits er en variabel som peker til et oppslagsverk, der nøklene er ulike grener av en fruktbutikkjede, og verdiene er lister over frukt som er tilgjengelig for kjøp på en bestemt arbeidsdag. Den mest solgte frukten i kjeden er pakket inn i *asterisker*. Eksempel på fruits nedenfor; merk at antallet tilgjengelige frukter hver dag er forskjellig.

Illustrasjon av fruits
Oppgave

Skriv en funksjon top_fruits med en parameter fruits på formatet beskrevet over. Funksjonen skal returnere et oppslagsverk med frukter som nøkler og hvor mange ganger de var bestselgere som verdi.

Eksempel på forventet returverdi dersom eksempelet på fruits over blir brukt som argument til funksjonskallet:

{
    'Apple': 3,
    'Orange': 2,
    'Banana': 4,
    'Ananas': 3,
    'Mango': 1,
    'Kiwi': 1,
    'Papaya': 1,
}

def top_things(data):
    counter = {}
    for key in data:
        for string_of_things in data[key]:
            list_of_things = string_of_things.split(',')
            for thing in list_of_things:
                thing = thing.strip()
                if thing[0] == '*' == thing[-1]:
                    core = thing[1:-1]
                    if core not in counter:
                        counter[core] = 0
                    counter[core] += 1
    return counter

Avhengig av hvilken versjon av oppgaven som brukes, er det naturlig at variabelnavnene er forskjellige. For eksempel:

def top_things(fruits):
    counter = {}
    for store in fruits:
        for day in fruits[store]:
            fruits_sold = string_list.split(',')
            for fruit in fruits_sold:
                fruit = fruit.strip()
                if fruit[0] == '*' == fruit[-1]:
                    fruit_bestseller = fruit[1:-1]
                    if fruit_bestseller not in counter:
                        counter[fruit_bestseller] = 0
                    counter[fruit_bestseller] += 1
    return counter

Den komplette løsningen er relativt kompleks, og inneholder flere detaljer det kan være fort gjort å glemme. Sensor skal overse dersom kandidaten har glemt strip eller gjort enkle syntaks-feil

  • 1 poeng: en løkke gjennom nøkler (eller verdier) i oppslagsverket (for eksempel for key in data)
  • 1 poeng: man henter ut verdiene for hver nøkkel på riktig måte (eller bruker direkte en løkke over verdiene i oppslagsverket) (for eksempel data[key] eller bruk av for my_list in data.values())
  • 2 poeng: en nøstet løkke gjennom listene som er verdier i oppslagsverket (for eksempel for string_of_things in data[key])
  • 1 poeng: bruk av split eller lignende for å dele opp strengen til en liste av ting.
  • 1 poeng: dobbel-nøstet løkke gjennom listen av ting som kommer fra strengen (for eksempel for thing in string_of_things.split(','):).
  • 2 poeng: fornuftig sjekk av om en streng er omsluttet av *asterisker* (for eksempel if thing[0] == '*':, det er ikke nødvendig å sjekke begge sider for full pott siden det er rimelig å anta at asterisk ikke brukes til noe annet)
  • 1 poeng: oppretter struktur for telling på en god måte (for eksempel counter = {} før løkkene begynner)
  • 1 poeng: oppdaterer struktur for telling på en god måte når man møter en ny type element for første gang (for eksempel if thing not in counter: counter[thing] = 0)
  • 1 poeng: oppdaterer struktur for telling på en god måte når man møter et element man har sett før (for eksempel counter[thing] += 1)
  • 2 poeng: helhetsvurdering
(3.3)  Rense CSV (18 poeng)

0.132;3.500;A;Jeg går imellem ranke, nakne stammer.
3.600;6.200;B;De blanke knopper løfter sig i lyset ind
6.300;8.000;B;og drikker grådig aftensolens <<ERROR>>skin,
8.100;11.000;A;som lavt på vårens bleke himmel flammer.
...

Sigrid Undset er en av 1900-tallets mest fremtredende og internasjonalt anerkjente norske forfattere. Forfatterskapet hennes består hovedsakelig av samtidsromaner og noveller, samt historiske romaner som utspiller seg i middelalderen. Hun ble tildelt Nobelprisen i litteratur i 1928, og skilte seg ut som en av de få kvinnelige prisvinnerne i sin samtid. Nobelkomiteen fremhevet hennes «sterke skildringer av middelalderlivet i Norden» som et vesentlig aspekt ved hennes litterære innsats. Hennes mest kjente verk er Kristin Lavransdatter, en trilogi om livet i Norge i middelalderen, skildret gjennom en kvinnes livslange erfaringer.

Filen poetry.csv inneholder data om et lydopptak av en diktlesning av «Ave» av Sigrid Undset (de første par linjene vises over). Hver rad i filen inneholder

  • informasjon om når hver linje ble påbegynt og fullført i et lydopptak av diktet,
  • rimidentifikatoren (A, B eller C) og
  • selve diktlinjen.
Oppgavetekst
  1. Skriv en funksjon read_poetry_data med en parameter path for filnavnet. Denne funksjonen skal lese filinnholdet og returnere en 2D-liste, der hver delliste tilsvarer en rad i CSV-filen.

  2. Skriv en funksjon clean_poetry_data med to parametre: table, en 2D-liste på formatet returnert av forrige deloppgave, og pattern_to_remove en streng som representerer et mønster som skal fjernes (for eksempel '<<ERROR>>'). Funksjonen skal destruktivt endre table slik at alle forekomster av mønsteret som skal fjernes blir borte. Funksjonen skal også skrive ut hvilke linjernummer som blir påvirket av dette.

  3. Skriv en funksjon rhyme_patters som beregner og returnerer et oppslagsverk som teller hvor mange forekomster det er av hvert rim-mønster i diktet. Hvert rim-mønster består av fire etterfølgende linjer, der navnet på rim-mønsteret hentes ut ved å konkatinere verdiene i den tredje kolonnen i CSV-filen (f. eks. er ‘ABBA’ et rim-mønster i første vers).

Deloppgave 1

I denne deloppgaven er det omtrent bare å kopiere de to linje du trenger fra kursnotatene. Denne operasjonen er helt grunnleggende og hva vi kopierer er såpass kort at det ikke er behov for å sitere.

from pathlib import Path
import csv
import io

def read_csv(path):
    file_content = Path(path).read_text(encoding='utf-8')
    reader = csv.reader(io.StringIO(file_content), delimiter=';')
    return list(reader)
Deloppgave 2
def clean_data(table, pattern_to_remove):
    for i, row in enumerate(table):
        row_affected = False
        for j, val in enumerate(row):
            if pattern_to_remove in val:
                clean_value = val.replace(pattern_to_remove, '')
                row[j] = clean_value
                row_affected = True
        if row_affected:
            print(f'Mønster fjernet fra rad {i}')
Deloppgave 3
def count_patterns(table):
    counter = {}
    pattern_length = 4
    pattern_column = 2
    for i_start in range(len(table) - pattern_length + 1):
        pattern = ''
        for i in range(i_start, i_start + 4):
            pattern += table[i][pattern_column]
        if pattern not in counter:
            counter[pattern] = 0
        counter[pattern] += 1
    return counter
  • (4 poeng) del 1
  • (7 poeng) del 2
  • (7 poeng) del 3