Eksamen

11. mai 2026
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.
 

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.

1 Automatisk rettet

Finn riktig datatype til hvert uttrykk (eller identifiser Error)

x = {'count':3}
y = [8, x]
w = ['strawberry']
[42, True, x]
'brush' in 'toothbrush'
f'{123}'
x['count']/2
len(w[0])
{99, 40, 1}
y[1]
x.pop(3)

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

x = 10
y = '10'
u = [True, 2, 3]
w = {
  'cba': 2,
  10: u,
}
s = 'cba'

Anta at kodesnutten over har blitt kjørt, og at en av setningene under er den neste setningen som utføres. Hva skrives ut? Hvis programmet krasjer, skriv kun Error.

(Husk at apostrofer og hermetegn som omgir strenger i kildekoden ikke er blir inkludert i utskriften.)

print(x != y) 
print(not u[0])
print(y + y)
print(y[0])
print(s[-1])
print(u[1:])
print(s*w[s]) 
print(w[x][2]) 

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

def f(y):
  y *= 2
  return y

def g(x):
  x = f(x)
  return f(x) + x

Anta at funksjonene over er definert. Hva evaluerer disse uttrykkene til? (hvis uttrykket krasjer, skriv kun Error)

f(3)
g(4)
f(g(1))

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

def update(x, y):
  if x - y > 50:
    return 2*y
  elif x - y < 50:
    y += 50
  else:
    x -= 50
    print(y)
  return y // x

x = 100
y = x + 50

Anta at kodesnutten over har blitt kjørt, og at setningen under er den neste setningen som utføres. Hva skrives ut? Hvis programmet krasjer, skriv kun Error.

print(update(x,y))

Klikk på det grå feltet for å se svaret.

def f(x, y):
  result = []
  for num in x:
    if num % y == 0:
      result.append(num // y)
    else:
      result.append(num)
  return result

a = [8, 10, 36, 25]
b = f(a, 5)

Anta at kodesnutten over har blitt kjørt, og at en av setningene under er den neste setningen som utføres. Hva skrives ut? Hvis programmet krasjer, skriv kun Error.

print(a)
print(b)
print(f(f(a,5),5))

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

x = 20
y = 1

while x > 0:
  x -= 2
  if x % 4 == 0:
    continue
  if x < 10:
    break
  y = 1 - y

Anta at kodesnutten over har blitt kjørt, og at setningen under er den neste setningen som utføres. Hva skrives ut? Hvis programmet krasjer, skriv kun Error.

print(x+y)

Klikk på det grå feltet for å se svaret.

Denne oppgaven handler om presedens og assosiativitet. Hvordan plassere parenteser for å få et uttrykk identisk med x or not y and z or w

x or ((not (y and z)) or w)
(x or ((not y) and z)) or w
(x or (not (y and z))) or w
x or (((not y) and z) or w)

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

2 Forklaring
8  Bedre funksjonsnavn (5 poeng)

Et revolusjonært komité har tatt makten. De ga i oppdrag å utvikle følgende program for å administrere lederskapet:

def foo(lst):
  last = lst[-1]
  for i in range(len(lst) - 1, 0, -1):
    lst[i] = lst[i - 1]
  lst[0] = last

names = ["Bashar", "Robert", "Fidel", "Vladimir", "Kim"]
foo(names)
print(names)
  • Hva gjør funksjonen foo()? Hva skriver programmet ut? 
  • Gi funksjonen foo() et bedre navn, slik at folk enkelt kan forstå hva funksjonen gjør uten å vite hvordan den er implementert. 
  • Funksjonen flytter det siste elementet i listen til første posisjon og forskyver alle de øvrige elementene én plass mot høyre i listen.
  • Programmet skriver ut [“Kim”, “Bashar”, “Robert”, “Fidel”, “Vladimir”]
  • Et bedre navn for denne funksjonen kan være rotate. Navnet må uttrykke betydningen av å rotere eller forskyve.
  • (2 poeng) Hva gjør funksjonen foo()? 
  • (1 poeng) Hva skriver programmet ut? 
  • (2 poeng) Gi funksjonen foo() et bedre navn, slik at folk enkelt kan forstå hva funksjonen gjør uten å vite hvordan den er implementert. 
9  Finn feilene (5 poeng)

Størrelsen på et embryo måles i de første ukene av svangerskapet ved hjelp av CRL (crown-rump length) – avstanden fra toppen av hodet til enden av ryggraden. En lege ønsker å estimere CRL-verdiene for neste trimester basert på en forventet vekstfaktor. Følgende funksjon brukes til å beregne dette:

def times_factor(crl_measurements, factor):
  new_lst = []
  for sub_lst in crl_measurements:
    new_sub_lst = []
    for num in sub_lst:
      new_sub_lst.append(num*factor)
    new_lst.append(new_sub_lst)
  return new_lst

data = [[12, 16, 21], [38, 45, 52]]
times_factor(data, 10)
print(data)
  • Kjøringen gir outputen [[12, 16, 21], [38, 45, 52]], som ikke var forventet. Hva tror du den forventede utskriften burde være?
  • Hvorfor klarer ikke programmet å gjøre dette?
  • Hvordan vil du fikse det?
  • Den forventede utskriften burde være [[120, 160, 210], [380, 450, 520]].
  • times_factor er en ikke-destruktiv funksjon. Det muterer ikke parameteren crl_measurements. Så listen data blir ikke endret, og print(data) vil skrive ut nøyaktig den samme listen som var argumentet til funksjonen times_factor.
  • Problemet er at det mangler en variabel for å lagre returverdien fra times_factor. Den korrigerte koden kan være:
def times_factor(crl_measurements, factor):
  new_lst = []
  for sub_lst in crl_measurements:
    new_sub_lst = []
    for num in sub_lst:
      new_sub_lst.append(num*factor)
    new_lst.append(new_sub_lst)
  return new_lst

data = [[12, 16, 21], [38, 45, 52]]
predicting_data = times_factor(data, 10)
print(predicting_data)

En annen løsning er å omskrive funksjonsimplementasjonen slik at den blir destruktiv:

def times_factor(crl_measurements, factor):
  for sub_lst in crl_measurements:
    for i in range(len(sub_lst)):
      sub_lst[i] *= factor

data = [[12, 16, 21], [38, 45, 52]]
times_factor(data, 10)
print(data)
  • (1 poeng) Hva tror du den forventede utskriften burde være?
  • (2 poeng) Hvorfor klarer ikke programmet å gjøre dette?
  • (2 poeng) Hvordan vil du fikse det?
10  Lister i minnet (5 poeng)
Illustrasjon av variabler og minnets tilstand slik det skal gjenskapes

Skriv ein kodesnutt slik at minnet får den tilstanden som er vist ovanfor. For full pott må du løse oppgaven uten å bruke hjelpevariabler/andre variabler enn a og b. (bilde er hentet fra Python Tutor).

a = [20, [30, [40]]]
b = [[10], a[1][1]]

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

Vi teller poengene slik:

  • (2 poeng) a har verdi [20, [30, [40]]]
  • (1 poeng) b har verdi [[10], [40]]
  • (2 poeng) b[1] og a[1][1] peker på nøyaktig det samme liste i minnet

Du får 5 poeng for en korrekt løsning dersom du løser oppgaven uten å bruke hjelpevariabler eller andre variabler enn a og b, slik at uttrykket nedenfor evaluerer til True.

(
  a == [20, [30, [40]]] and 
  b == [[10], [40]] and
  b[1] is a[1][1] and 
  type(b[0]) == list and 
  type(b[1]) == type(a[1][1]) == list
)

Hvis du bruker andre variabler enn a og b men disse variablene finnes ikke i rammene til slutt, vil du få 4 poeng. For eksempel,

c = [40]
d = [30, c]
e = [10]
a = [20, d]
b = [e, c]
del c
del d
del e

Hvis du bruker andre variabler enn a og b men disse variablene blir fortsatt værende i rammene til slutt, vil du få 3 poeng. For eksempel,

c = [40]
d = [30, c]
e = [10]
a = [20, d]
b = [e, c]

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

3 Kodeskriving
11  Telle bokstaver - 1 (5 poeng)

Skriv en funksjon count_letter(letter, wordlist) som teller hvor mange ganger en gitt bokstav forekommer i en liste med ord. For eksempel forekommer bokstaven ‘b’ totalt 5 ganger i listen [‘stubborn’, ‘house’, ‘cabbage’, ‘job’, ’exam’].

I denne oppgaven kan du prøve koden du skriver mot noen tester underveis i eksamen. Testene blir kjørt når du trykker på knappen «test kode» under kodefeltet. Dersom du ikke passerer alle testene, kan likevel sensor gi delvis uttelling etter en manuell vurdering.

Test case # Input Forventet output
1 count_letter(‘b’, [‘stubborn’, ‘house’, ‘cabbage’, ‘job’, ’exam’]) 5
2 count_letter(‘k’, [‘bookkeeping’, ’lake’, ‘kickoff’, ’tree’, ‘rucksack’]) 7
3 count_letter(‘b’, [‘house’, ’tree’, ‘car’, ’light’]) 0

Startkode:

def count_letter(letter, wordlist):
  # Skriv koden her
  # ...
    
# IKKE rediger under denne linjen!
print(eval(input()))
def count_letter(letter, wordlist):
  num = 0
  for word in wordlist:
    for l in word:
      if l == letter:
        num += 1
  return num
def count_letter(letter, wordlist):
  num = 0
  for word in wordlist:
    num += word.count(letter)
  return num
def count_letter(letter, wordlist):
  num = 0
  for i in range(len(wordlist)):
    num += wordlist[i].count(letter)
  return num
  • (2 poeng) Riktig bruk av løkke(r) som går igjennom elementene i listen
  • (2 poeng) Tell antall forekomster av den gitte bokstaven. Startverdien til tellevariabelen er 0.
  • (1 poeng) Funksjonen returnerer resultatet. return-setningen skal være utenfor løkkene.
12  Telle bokstaver - 2 (5 poeng)

Fortsett med den forrige oppgaven (Oppgave 11).

Skriv en funksjon count_letters(data).

  • data er en liste med tupler på formen (letter, wordlist)

Funksjonen skal returnere en liste med heltall, der hvert tall angir hvor mange ganger den tilhørende bokstaven forekommer i sin ordliste.

I denne oppgaven kan du prøve koden du skriver mot noen tester underveis i eksamen. Testene blir kjørt når du trykker på knappen «test kode» under kodefeltet. Dersom du ikke passerer alle testene, kan likevel sensor gi delvis uttelling etter en manuell vurdering.

Test case # Input Forventet output
1 count_letters([(‘b’, [‘stubborn’, ‘house’, ‘cabbage’, ‘job’, ’exam’]),(‘k’, [‘bookkeeping’, ’lake’, ‘kickoff’, ’tree’, ‘rucksack’])]) [5,7]
2 count_letters([(‘b’, [‘stubborn’, ‘house’, ‘cabbage’, ‘job’, ’exam’]), (‘b’, [‘house’, ’tree’, ‘car’, ’light’]), (‘k’, [‘bookkeeping’, ’lake’, ‘kickoff’, ’tree’, ‘rucksack’])]) [5,0,7]

Startkode:

def count_letters(data):
  # Skriv koden her
  # ...
    
# IKKE rediger under denne linjen!
print(eval(input()))
def count_letter(letter, wordlist):
  num = 0
  for word in wordlist:
    for l in word:
      if l == letter:
        num += 1
  return num

def count_letters(data):
  result = []
  for letter, wordlist in data:
    result.append(count_letter(letter, wordlist))
  return result
def count_letter(letter, wordlist):
  num = 0
  for word in wordlist:
    for l in word:
      if l == letter:
        num += 1
  return num

def count_letters(data):
  result = []
  for letter, wordlist in data:
    result += [count_letter(letter, wordlist)]
  return result
  • (2 poeng) Hent dataene korrekt fra hver tuple
  • (2 poeng) Funksjonen skal returnere en liste med heltall, der hvert tall angir hvor mange ganger den tilhørende bokstaven forekommer i sin ordliste.
  • (1 poeng) return-setningen skal være utenfor løkkene

Det er tillatt å bruke funksjonen count_letter(letter, wordlist) i denne oppgaven uten å måtte skrive selve koden for funksjonen på nytt.

13  Vanninntak - 2 (10 poeng)

Skriv et Python-program som leser en CSV-fil med personopplysninger, og beregner hver enkelt persons anbefalte daglige vanninntak (i milliliter).

Vektbasert (metrisk): Multipliser vekten (kg) med 30 (ml/kg). (For eksempel: 70 kg * 30 ml/kg = 2100 ml per dag)

Anta at du har en fil health.csv med innholdet nedenfor:

Name;Weight(kg)
Henrik;70
Ingrid;52
Mathias;85
Svanhild;60

Utskriften fra programmet ditt bør være en liste med oppslagsverker:

[{"Name":"Henrik", "Weight(kg)":70,"Water":2100},
 {"Name":"Ingrid", "Weight(kg)":52,"Water":1560},
 {"Name":"Mathias", "Weight(kg)":85,"Water":2550},
 {"Name":"Svanhild", "Weight(kg)":60,"Water":1800}]
from pathlib import Path

def main():
  content_string = Path('health.csv').read_text(encoding='utf-8')
  content = content_string.splitlines()
  header = content[0].split(';')
  body = content[1:]

  result = []

  for person in body:   
    data = person.split(';')
    new_data = {} 
    for i in range(len(header)):
      if header[i] == "Weight(kg)":
        new_data[header[i]] = int(data[i])
      else:
        new_data[header[i]] = data[i]
    new_data['Water'] = water_intake(new_data["Weight(kg)"])
    result.append(new_data)

  print(result)

def water_intake(w):
  return w * 30

if __name__ == '__main__':
  main()
from pathlib import Path
import csv 
import io

def main():
  content_string = Path('health.csv').read_text(encoding='utf-8')
  reader = csv.DictReader(io.StringIO(content_string), delimiter=';')
  data = list(reader)  

  for person in data:
      person["Weight(kg)"] = int(person["Weight(kg)"])
      person['Water'] = water_intake(person["Weight(kg)"])

  print(data)

def water_intake(w):
  return w * 30

if __name__ == '__main__':
  main()
  • (2 poeng) Les csv-filen på fornuftig måte
  • (1 poeng) Bruke konverteringsfunksjonen int() for vektverdiene
  • (2 poeng) Lag en formel for å beregne det daglige vanninntaket
  • (2 poeng) Vanninntaket er korrekt lagt inn i oppslagsverkene
  • (2 poeng) Alle nøkkel–verdi-parene i oppslagsverkene er korrekte
  • (1 poeng) Utskriften fra programmet er en liste med oppslagsverker
14  Ruteringsproblem (15 poeng)

Et logistikkselskap har gitt deg data om sine leveringsruter og trenger at du skriver en rapport.

Anta at du har en fil routes.json med innholdet som er vist nedenfor.

{
"1" : { "planned_idx": [...],  "actual_idx": [...], "distances": [...] }, 
"2" : {
       "planned_idx": [
            0,
            1,
            2
        ],
        "actual_idx": [
            0,
            2,
            1
        ],
        "distances": [
            [
                0,
                30870,
                31775
            ],
            [
                31004,
                0,
                1499
            ],
            [
                32054,
                1625,
                0
            ]
        ]
    },
..., 
"100" : { "planned_idx": [...],  "actual_idx": [...], "distances": [...] }
}

I routes.json inneholder hver datapost tre opplysninger: den planlagte ruten som sjåføren fikk fra logistikkfirmaet, ruten som sjåføren faktisk endte opp med å kjøre, og avstandsmatrisen. Hver kunde er identifisert med et unikt id-nummer.

For eksempel, i dataposten “2” angir den planlagte ruten at sjåføren skal levere pakkene i følgende rekkefølge: kunde 0, deretter kunde 1, og til slutt kunde 2. Sjåføren fulgte derimot en annen rute: kunde 0, deretter kunde 2, og til slutt kunde 1. For enkelhets skyld viser vi kun dataposten “2” og representerer innholdet i de andre datapostene med ellipser (…).

Indeksene i avstandsmatrisen representerer kundenes id. Hver rad viser avstandene fra én kunde til alle de andre kundene i ruten. For eksempel, i rad 0 i avstandsmatrisen for dataposten “2”, er avstanden fra kunde 0 til seg selv 0, avstanden fra kunde 0 til kunde 1 er 30870, og avstanden fra kunde 0 til kunde 2 er 31775.

Anta at routes.json inneholder 100 dataposter, og at listene planned_idx og actual_idx har samme lengde i hver datapost. For hver datapost, beregn den totale avstanden for den planlagte ruten og den faktiske ruten ved å bruke den oppgitte avstandsmatrisen. Deretter sammenlignes de to totalsummene, og man holder oversikt over hvor mange ganger:

  • den faktiske ruten er kortere enn den planlagte ruten,
  • den planlagte ruten er kortere enn den faktiske ruten, og
  • begge rutene har lik total avstand.

I tillegg ønsker logistikkfirmaet å vite den totale avstanden som ble spart av sjåførene i tilfeller der den faktiske ruten er kortere enn den planlagte. Summer disse besparelsene for alle slike dataposter.

from pathlib import Path
import json

def main():
  content_string = Path('routes.json').read_text(encoding = 'utf-8')
  content = json.loads(content_string)

  planned_shorter = 0
  actual_shorter = 0
  equal = 0
  distance_saved = 0

  for data_entry_id in content:
    info = content[data_entry_id]

    planned_distance, actual_distance = calculate_distances(info["planned_idx"], info["actual_idx"], info["distances"])

    if actual_distance < planned_distance:
      actual_shorter += 1
      distance_saved += (planned_distance - actual_distance)
    elif planned_distance < actual_distance:
      planned_shorter += 1
    else:
      equal += 1

  print(f'{actual_shorter} routes had a shorter actual route')
  print(f'{planned_shorter} routes had a shorter planned route')
  print(f'{equal} routes were equal')
  print(f'{distance_saved} distance are saved in total')

def calculate_distances(planned, actual, distances):
  planned_distance = 0
  actual_distance = 0
  for i in range(len(planned)-1):
    planned_distance += distances[planned[i]][planned[i+1]]
  for i in range(len(actual)-1):
    actual_distance += distances[actual[i]][actual[i+1]]
  return (planned_distance, actual_distance)

if __name__ == '__main__':
  main()
  • (1 poeng) Les json-filen på fornuftig måte
  • (6 poeng) Beregne den totale avstanden for den planlagte ruten og den faktiske ruten for hver datapost. Koden skal kunne håndtere et vilkårlig antall kunder. Men vi trekker ikke poeng hvis koden din bare kan håndtere 3 kunder.
    • (2 poeng) Hent listene over planned_idx, actual_idx og distances i en datapost
    • (2 poeng) Bruk innholdet i en ruteliste som indekser i den todimensjonale avstandsmatrisen for å hente ut avstanden mellom to kunder.
    • (2 poeng) Beregne den totale avstanden for en ruteliste
  • (3 poeng) Sammenlign den planlagte ruten og den faktiske ruten for hver datapost, ett sammenligningstilfelle hver
  • (2 poeng) Summer opp tallene på tvers av alle datapostene. Siden vi antar at det finnes 100 dataposter i routes.json, er det greit å definere en løkke som iterere nøyaktig 100 ganger.
  • (1 poeng) Beregn den totale avstanden som sjåførene sparer

Til slutt gjøres en helhetsvurdering verdt 2 poeng. Sensor vurderer her helheten av besvarelsen og om delene fungerer i sammenheng. For eksempel, sensor vil vurdere om kode­strukturen er god, om koden er lett å lese og forstå, og om det brukes gode variabelnavn. Sensor skal ikke trekke for syntaksfeil dersom intensjonen er tydelig og algoritmen er presist beskrevet, men ser på om programmet som helhet henger sammen og er logisk strukturert.