4. Moment04 - Iterationer och listor

Info

Till detta moment finns en sida med lösningsförslag och videoklipp.

För de elever som vill utmanas ytterligare med fler och/eller svårare uppgifter hittar dessa här.

Iteration

Iteration är ett annat ord för upprepning. Inom matematiken och i programmering handlar detta om att en funktion eller process åstadkommer något genom att upprepa beräkningar eller andra operationer tills ett önskat resultat uppnåtts.
https://sv.wikipedia.org/wiki/Iteration (avläst 2018-11-04)

Det finns flera olika strukturer när vi skapar iterationer inom programmeringen, de är bra på olika saker så för att få den mest effektiva koden behöver du kunna använda flera olika typer. När det gäller Python så finns det två olika typer av iterationer som vi behöver kunna.

4.1 for-loopen

For-loopen är den mest styrda loopen, här ligger fokus på att en operation genomförs x antal gånger. Vi börjar med ett exempel.

Kodexempel: enkel for-loop, anger antalet gånger loopen körs

for i in range (5):
    print(i)

for-kommandot innebär att det är en for-loop vi vill köra. i får värdet som iteratorn (räknaren) har i varje varv. Och in range (5) innebär att vi skall räkna från början, vilket är 0 eftersom det lägsta talet inom programmering är 0, och köra vår loop 5 gånger. För bättre tydlighet skulle vi kunna skriva koden på följande sätt;

Kodexempel: enkel for-loop, bestämt start- och slutvärde

for i in range (0, 5):
    print(i)

Alltså: Kör en loop, börja med att i får värdet 0 och kör loopen 5 gånger (egentligen kör mot 5 men stannar innan 5 körs). Utskrifterna skulle i bägge fallen bli.

Utskrift

0
1
2
3
4

Att kunna utföra en viss operation flera gånger är något som ofta används inom programmeringen. Just nu kör vi en loop ganska få gånger men vid statistiska beräkningar så kan loopen bestå av enormt stora datamängder. Vi skall senare kika lite på hur vi kan loopa igenom en lista istället för att följa en talserie.

Men om vi nu vill följa en dataserie men inte använda alla tal i vår beräkning så kan vi på ett enkelt sätt ta större steg än 1 i vår loop.

Kodexempel: enkel for-loop, bestämda steg

for i in range (0, 15, 3):
    print(i)

Utskriften blir då.

Utskrift

0
3
6
9
12

När vi kör vår for-loop så finns det ett kommando som körs när loopen har kört färdigt och innan skriptet fortsätter utanför loopen och det är kommandot else. OBS: Blanda nu inte ihop det med else som används vid selektioner.

Kodexempel: for-loop med else

summa = 0
for i in range (0, 15, 3):
    print(i)
    summa += i
else:
    print("Summan av alla talen är", summa)

Utskriften blir då.

Utskrift

0
3
6
9
12
Summan av alla talen är 30

I detta fallet så hade vi fått samma resultat och utskrift om vi hade skrivit koden på följande sätt;

Kodexempel: for-loop utan else

summa = 0
for i in range (0, 15, 3):
    print(i)
    summa += i

print("Summan av alla talen är", summa)

Återigen ett exempel på hur vi kan skriva kod på olika sätt för att få fram samma resultat. Lägg här märke till rad 6 där koden inte har någon indentering och därför inte tillhör loopen. Det finns tillfällen då else är extra intressant och det kikar vi på senare.

Vi har sett att det finns tre olika parametrar till vår for-loop och hittills har vi bara räknat uppåt. Det går naturligtvis också att räkna nedåt, det viktigaste då är att vi ser till att vi har ett korrekt startvärde och slutvärde så att det går att loopa mellan dessa tal. Går det inte att loopa så kommer inte loopen att köras.

Kodexempel: for-loop räknar nedåt

summa = 0
for i in range (10, 3, -3):
    print(i)
    summa += i

print("Summan av alla talen är", summa)

Vi kör vår loop från talet 10 till talet 3 där varje steg minskas med 3. Utskriften blir då.

Utskrift

10
7
4
Summan av alla talen är 21

Testa vad som händer om du byter plats på parameter 1 och 2 eller gör parameter 3 till positiv.

Uppgift: m04u01

Skriv ut alla tal från 1 till 10, i steg om 2, med hjälp av en for-loop.

Multiplicera sedan värdet på alla dessa tal och skriv ut svaret.

Vidareutveckling: kodkalendern 2021, lucka 1

Med m04u01 som grund så går det att bygga vidare för att lösa Unga programmerares kodkalender lucka 1 år 2021. Så det blir uppgiften, hitta den sexsiffriga pinkoden.

Uppgift: m04u02

Ulf har satt in 10 000kr på ett konto med 3 % årlig ränta, hur mycket pengar finns på kontot efter 15 år? Inga fler insättningar görs.
Välj själv hur du vill skriva ut svaret, med en enda rad efter färdig uträkning eller en rad för varje år.

Tips1: Under utveckling är det smart att skriva ut på varje rad för att se att du har tänkt, och beräknat, allt rätt.

Tips2: Om du inte vet hur du skall ställa upp din for-loop så fundera på hur du skulle lösa denna uppgiften på en matematiklektion utan miniräknare.

Fördjupning m04u02a [klicka för att visa]

Bygg ut applikationen så att sparbelopp, antal år och räntan går att mata in till systemet. Räntan vill jag ange som ett decimaltal, t.ex. 3,50%.

Fördjupning m04u02b [klicka för att visa]

För att utveckla applikationen ytterligare och skapa en sparsimulator så skulle jag vilja att du fixar möjlighet att spara nya pengar varje år. Om Ulf sätter in 0kr på kontot från början, nysparar 15000kr/år (barn-/studiebidraget) till 6.5% ränta i 18 år så har han 486151kr på kontot. Detta utgår ifrån att han inte får ränta på detta års insatta pengar, men på alla pengar som fanns där när året började.

4.1.1 Nästlade iterationer

Genomgång [klicka för att visa]

Vi har tidigare kikat på hur vi kan nästla selektioner vilket innebär en, eller flera, selektioner i en annan selektion. På samma sätt kan vi göra med kontrollstrukturen iterationer. Vi kan dessutom blanda hur vi vill nästla selektioner och iterationer, allt beror på uppgiften vi skall lösa.

Här kommer ett exempel på hur man kan nästla iterationer.

Kodexempel: 6:an och 7:ans multiplikationstabeller

# 6:an & 7:ans multiplikationstabeller
# Den yttre loopen tar hand om första talet, 6:ans tabell, 7:ans tabell
for i in range(6, 8):
    # Den inre loopen tar hand om alla tal mellan 0 och 10
    for j in range(0, 11):
        print(f"{i} * {j} = {i*j}")

    print()     # Skapar tomrad mellan de olika "tabellerna"

Det som behöver fokuseras främst på är kommenterat i koden ovan. Utskriften av programmet kommer här.

Utskrift

6 * 0 = 0
6 * 1 = 6
6 * 2 = 12
6 * 3 = 18

//
// bortklippta rader
//

7 * 8 = 56
7 * 9 = 63
7 * 10 = 70

På samma sätt som vi kan ha en iteration inne i en annan iteration så kan vi naturligtvis ocksp ha en selektion inne i en iteration.

Här kommer ett exempel på en selektion i en iteration där vi loopar från 10 till 20 men istället för att ta tre steg så väljer vi att skriva ut vart tredje tal med summan som alla tal skapar. Om vi kör tre steg i loopen så missar vi ju att summera de tal som inte stegas igenom vilket gör att resultatet blir felaktigt.

Kodexempel: for-loop räknar nedåt

# Deklarerar variabler
summa = 0
start = 10
stopp = 20
print(f"\nVi loopar från {start} till {stopp}.")
# Loopar från start till stopp
for i in range (start, stopp+1):
    summa += i
    # Om i är jämnt delbart med 3 skriver vi ut en delberäkning
    if i % 3 == 0:
        print(f"När i är {i} så är totalsumman {summa}")
# else som tillhör loopen och körs när loopen har körts färdigt
else:
    print(f"När vi loopat färdigt så är summan {summa}")

Det som behöver fokuseras främst på är kommenterat i koden ovan. Utskriften av programmet kommer här.

Utskrift

Vi loopar från 10 till 20.
När i är 12 så är totalsumman 33
När i är 15 så är totalsumman 75
När i är 18 så är totalsumman 126
När vi loopat färdigt så är summan 165

Uppgift: m04u03

Skapa en multiplikationstabell som ritar ut alla tal upp till tians multiplikationstabell. Viktigt här är att göra en bra formatering så att alla siffror inte flyter ihop. Se gärna exempelutskrift nedan.

Utbyggnad 1:Låt användaren mata in valfritt heltal för att bygga sin egen multiplikationstabell.

Utbyggnad 2: Hitta ett sätt så att multiplikationstabellen inte kan vara större än 15x15. Fundera på om det finns olika sätt att göra detta?

Utbyggnad 3: Om användaren matar in ett negativt heltal så ritas ingen multiplikationstabell ut, fundera på vilka alternativa lösningar som kan användas för att ändå rita ut. abs() kan vara ett alternativ? Vilka andra finns?

Utbyggnad 4: Det är så enkelt att göra en multiplikationstabell som är 5x5, 10x10 eller 12x12, men hur skulle du göra om användaren vill ha en multiplikationstabell som är tex 12x6?

Utskrift

Multiplikationstabell
   1   2   3   4   5   6   7   8   9  10
   2   4   6   8  10  12  14  16  18  20
   3   6   9  12  15  18  21  24  27  30
   4   8  12  16  20  24  28  32  36  40
   5  10  15  20  25  30  35  40  45  50
   6  12  18  24  30  36  42  48  54  60
   7  14  21  28  35  42  49  56  63  70
   8  16  24  32  40  48  56  64  72  80
   9  18  27  36  45  54  63  72  81  90
  10  20  30  40  50  60  70  80  90 100

4.1.2 Iteration som testmetod

En iteration kan ofta kan vara ett bra sätt att använda när vi kör tester på våra program. Vi skall kika på hur vi kan testa en uppgift som vi jobbade med i moment03. Uppgiften M03U04 handlade om att vi skulle hämta ett klockslag från datorn och sedan jämföra värdet på timmen för att se om det är före skoldag, efter skoldag eller om skoldagen pågår. Genom att skapa en iteration från 0 till 23 så är det lätt att se om vårt program fungerar som det är tänkt.

Kodexempel: for-loop för att testa applikation

# Loopar från klockan 0 till 23
for timme in range(0, 24):
    # Skriver ut vad klockan är men utan radbrytning
    print(f"Klockan är {timme}, ", end="")
    if timme < 8:
        print("skoldagen har inte börjat.")
    elif timme > 16:
        print("skoldagen är slut.")
    else:
        print("skoldagen pågår.")

Utskriften blir då.

Utskrift

Klockan är 0, skoldagen har inte börjat.
Klockan är 1, skoldagen har inte börjat.
// bortklippt //
Klockan är 7, skoldagen har inte börjat.
Klockan är 8, skoldagen pågår
// bortklippt //
Klockan är 16, skoldagen pågår
Klockan är 17, skoldagen är slut.
// bortklippt //
Klockan är 22, skoldagen är slut.
Klockan är 23, skoldagen är slut.

Den största fördelen här är att det nu är möjligt att testa hela applikationen utan att göra en manuell inmatning 24 ggr. Dessutom är det enkelt att testa de gränser som är intressanta för oss. I exemplet ovan så är det ju timvärden 7, 8, 16, 17 som vi är mest intresserade av att testa.

Uppgift: m04u03b

Bygg vidare på multiplikationstabellen som vi gjorde tidigare. Det talet som användaren matar in är det antal multiplikationstabeller som skall skrivas ut. Om användaren skriver in 3 så skall fört multiplikationstabellen för 1x1 skrivas ut, sedan för 2x2 och slutligen för 3x3.

Utskrift [klicka för att visa]

Ange vilken multiplikationstabell: 3

Multiplikationstabell upp till 1x1
   1

Multiplikationstabell upp till 2x2
   1   2
   2   4

Multiplikationstabell upp till 3x3
   1   2   3
   2   4   6
   3   6   9

4.2 while-loopen

Genomgång [klicka för att visa]

Den andra typen av loop som vi skall gå igenom är while-loopen. Här är det villkoret som är det styrande för hur länge loopen skall köras.

Kodexempel: while-loop

tal = 1

while tal < 5:
    print(tal)
    tal += 1

I exemplet så ser vi att uttrycket är tal < 5 och så länge detta gäller så kommer loopen att köras ett varv till. När vi jobbar med while-loopen så måste vi se till att det värde som finns i uttrycket måste förändras, vilket sker på rad 5, annars kommer loopen att bli oändlig. Utskriften i vårt exempel blir då.

Utskrift

1
2
3
4

Svårare än så är inte while-loopen och det viktigaste är att hålla koll på uttrycket eftersom det avgör om loopen skall köras en gång till. På samma sätt kan vi använda else för att göra något när villkoret inte längre ger värdet True och loopen avbryts.

Kodexempel: while-loop med else

tal = 1

while tal < 5:
    print(tal)
    tal += 1
else:
    print(f"När vi har loopat klart så har tal värdet {tal}")

Utskrift

1
2
3
4
När vi har loopat klart så har tal värdet 5

Använd else när det behövs.

Uppgift: m04u04

Skriv ut alla tal från 10 till 1 med hjälp av en while-loop.

Multiplicera sedan värdet på alla dessa tal och skriv ut svaret.

Uppgift: m04u05

Antalet råttor i en stad är 100 stycken, varje månad dubblas populationen av råttor, hur många månader dröjer det innan det finns en miljon råttor i staden? Lös uppgiften med en while-loop.

Tips: Under utveckling är det smart att skriva ut på varje rad för att se att du har tänkt, och beräknat, allt rätt.

4.2.1 Continue

Genomgång [klicka för att visa]

Ibland kan det vara så att vi vill använda en loop men av någon anledning inte genomföra en viss process ifall något uttryck gäller. Då kan vi använda kommandot continue som kommer hoppa över allt som kommer efter det kommandot i loopen och börja om loopen igen. Ett exempel;

Kodexempel: continue

tal = 0
while tal < 10:                 # kör så länge tal är mindre än 10
    tal += 1                    # öka tal med 1
    if tal % 2 == 0:            # om tal är jämnt delbart med 2 ..
      continue                  # .. starta om loopen
    print("Talet är", tal)     # skriv ut talet

print("Utanför loopen")

Utskrift

Talet är 1
Talet är 3
Talet är 5
Talet är 7
Talet är 9
Utanför loopen

Continue kan användas i både for-loopar och while-loopar.

Det finns ingen specifik uppgift för continue utan det kommer en efter avsnitt 4.2.2.

4.2.2 Break

Genomgång [klicka för att visa]

Kommandot break används på liknande sätt som continue fast istället för att börja om på nästa varv i loopen så avbryts loopen och programmet fortsätter efter loopen. Samma exempel som för continue fast med break.

Kodexempel: break

tal = 0
while tal < 10:                 # kör så länge tal är mindre än 10
    tal += 1                    # öka tal med 1
    if tal % 2 == 0:            # om tal är jämnt delbart med 2 ..
      break                     # .. avbryt loopen
    print("Talet är", tal)     # skriv ut talet

print("Utanför loopen")

Utskrift

Talet är 1
Utanför loopen

4.2.3 Pseduokod för loopar

Detta avsnitt skall byggas om

Eftersom vi har tagit bort aktivitetsdiagram så kommer detta avsnitt att byggas om.

Genomgång [klicka för att visa]

I filmen så gick jag även igenom aktivitetsdiagram, detta teknik har vi nu strukit ur kursen.

I förra momentet lärde vi oss att skriva pseudokod i sekvens och selektion. Nu har det blivit dags att lägga till iterationer (loopar). Egentligen är det uttrycket vi är intresserade av och sedan visar vi att det är en loop med hjälp av pilar. Jag visar med ett exempel och det är kodexempel: continue ovan som jag kommer använda som exempel.

Om vi skall skriva pseudokod för samma uppgift så kan den se ut så här.

  • Ge tal värdet 0
  • Om tal är mindre än 10
    • Öka talet med 1
    • Om tal inte är jämnt delbart med 2
      • Skriv ut talet
    • Annars kör ett varv till
  • Annars skriv ut att vi är utanför loopen

Den pseudokoden är väldigt lik kodexemplet, vilket den lätt blir om vi kodar först och skall skapa pseduokod efteråt. Om vi istället fokuserar på uppgiften och lösningen istället för koden så kanske pseduokoden ser ut så här.

  • Loopa igenom alla tal från 1 till 10
    • Om talet inte är jämnt delbart med 2
      • Skriv ut talet
  • Skriv ut att vi är utanför loopen

Här ser du två exempel på att vi kan skriva pseduokoden på lite olika sätt men ändå lösa samma uppgift. Det viktigaste är att du hittar ett sätt att lösa uppgiften.

Uppgift: m04u06

Denna uppgift kan kännas lite klurig men lös punkt för punkt nedan så går det lättare.

Låt användaren mata in följande tal;

  • Ett tal som loopen skall börja med.
  • Ett tal som loopen skall avsluta med.
  • Ett tal som inte skall skrivas ut.
  • Ett tal som skall avbryta loopen.

Bygg sedan detta program med en while-loop så att det fungerar enligt instruktionerna ovan.

Planera gärna uppgiften med pseudokod.

4.2.4 Felhantering, körtidsfel

Genomgång [klicka för att visa]

Tidigare har vi pratat om att syntaxfel är de fel som vi skriver i koden som gör att våra skript inte går att köra utan ger ett, eller flera, fel när vi försöker köra applikationen.

Nästa feltyp vi behöver lära oss ta hand om är körtidsfel och de är fel som kraschar en applikation medan den körs. Vi har stött på detta när vi matar in någonting annat än vad vår applikation förväntar sig. Ofta blir det fel när vi skall mata in ett heltal och matar in någonting som inte kan konverteras till ett heltal.

Det som löser detta problem för oss är en kontrollstruktur som egentligen är en variant av selektion och som passar väldigt bra ihop med iterationer. Strukturen är en try-except (try-catch i många andra programmeringsspråk) och den provar att göra någonting, om det fungerar så är allt frid och fröjd och applikationen kan fortsätta, fungerar det inte så har vi möjlighet att skriva kod som talar om vad vi vill skall hända då. En felaktig inmatning, eller en felaktig inläsning från en fil, gör ju att vår applikation kraschar lite senare och det vill vi ju inte, då är det bättre att ta kontroll på inmatningen så att den går rätt till. Vi kör ett exempel.

Kodexempel: try-except

# loopen kommer "alltid" köras eftersom uttrycket är True
while True:
    try:        # detta block är det som testas, blir det fel här...
        tal = int(input("Ange ett heltal: "))
        break   # avbryter loopen
    except:     # ... hamnar vi här istället
        print("Det blev fel, försök igen")
# Utanför loopen sker utskriften
print(f"Det korrekt inmatade talet är {tal}")

Utskrift

Ange ett heltal: tre
Det blev fel, försök igen
Ange ett heltal: 3.2
Det blev fel, försök igen
Ange ett heltal: 3,2
Det blev fel, försök igen
Ange ett heltal: 3
Det korrekt inmatade talet är 3

Koden och kommentarerna borde räcka för att förklara vad som händer. Detta är ett smidigt sätt att undvika krascher i våra applikationer.

Uppgift: m04u07 (svårare)

Bygg vidare på m04u06 så att användaren inte kan mata in felaktiga värden. Kolla både att datatypen är rätt men också att de inmatade värdena är korrekta i förhållande till varandra, alltså att stoppvärdet är större än startvärdet (annars måste vi förändra steglängden så att den blir negativ) och att tal som skall hoppas över och avbryta loopen måste finnas inom intervallet mellan start- och stoppvärdet.

4.3 Listtyper

Genomgång [klicka för att visa]

Olika typer av listor är vanliga i de flesta programmeringsspråk. Orsaken till detta är att vi ofta behöver bearbeta en stor mängd data och då är det inte praktiskt att skapa variabler för all denna data. Tänk att en klass har genomfört ett prov och du nu skall göra ett antal beräkningar av denna data. Då är det inte vettigt att skapa en variabel för varje resultat; res1 = 14, res2 = 19 osv. För detta ändamål används någon form av lista. I python har vi fyra olika listtyper; list, tuple, set och dictionary. Det är främst de två första som vi kommer kika på och det är list som vi kommer lägga mest tid på att använda.

4.3.1 List

Genomgång [klicka för att visa]

En lista kan du se som en variabel med flera fack (element), i varje element kan det lagras ett värde. Om vi går tillbaka till exemplet om att samla provresultat så kommer varje resultat hamna i var sitt element i den listan som du har skapat. I de flesta listtyper kommer varje element ha ett id som gör att vi kan hålla ordning på i vilket element ett visst värde finns.

4.3.1.1 Skapa

Att skapa en lista är enkelt, du skapar en variabel men anger värden med hjälp av klammer och separerar värden med kommatecken.

Kodexempel: skapa list

resultat = [12, 19, 22, 4, 0]

På detta sättet skapar vi en lista med fem resultat.

4.3.1.2 Skriv ut hela

Om vi vill skriva ut vår lista så går det att skriva ut variabelns värde vilket kommer se ut på precis samma sätt som vi skrev in den.

Kodexempel: skriv ut list

resultat = [12, 19, 22, 4, 0]
print(resultat)

Utskrift

[12, 19, 22, 4, 0]

Det går också att skriva ut varje element för sig genom att loopa igenom listan.

Kodexempel: skriv ut list individuellt

resultat = [12, 19, 22, 4, 0]

# Loopar igenom resultat med en for-loop
for r in resultat:    # Låt r lagra nästa element i listan resultat
    print(r)

Utskrift

12
19
22
4
0

Det är också möjligt att lagra olika datatyper i en list.

Kodexempel: list med olika datatyper

data = [21, "Programmering01", [2, 3, 4, 5], False, 3.14]
print("Skriv ut innehållet:", data)
print("\nSkriv ut datatyperna i listan")
for d in data:
    print(d, "är av typen", type(d))

Utskrift

Skriv ut innehållet: [21, 'Programmering01', [2, 3, 4, 5], False, 3.14]

Skriv ut datatyperna i listan
21 är av typen <class 'int'>
Programmering01 är av typen <class 'str'>
[2, 3, 4, 5] är av typen <class 'list'>
False är av typen <class 'bool'>
3.14 är av typen <class 'float'>

I exemplet så skapar jag en lista med fem värden. Värt att notera är att list är en datatyp vilket gör det möjligt att lagra en lista i en lista.

4.3.1.3 Enskilt element

För att kunna anropa ett enskilt element i en lista så behöver dessa identifieras på något sätt. I en list så identifieras de med ett index och det kan vi använda om vi vill skriva ut ett särskilt värde. Indexen i en list börjar numreras från 0.

Kodexempel: list och index

cities = ["Göteborg", "Alingsås", "Borås"]
print("Pelle bor i", cities[1])
cities[1] = "Vårgårda"
print(cities)

Utskrift

Pelle bor i Alingsås
['Göteborg', 'Vårgårda', 'Borås']

Här visar jag hur du kan skriva ut värdet för index 1 (position 2) i cities och sedan ändra värdet på detta index.

Ibland kan det vara bra att kunna skriva ut både index och värdet. En sådan enkelt utskrift som nedan är inget vi vill ha i en färdig applikation men det kan vara skönt att göra utskriften under utveckling.

Kodexempel: värde och index i en list

cities = ["Göteborg", "Alingsås", "Borås"]
for index, value in enumerate(cities):
    print(index, value)

Utskrift

0 Göteborg
1 Alingsås
2 Borås

Enumerate() är en inbyggd funktion som skapar en räknare till den datatyp som vi itererar igenom.

Ofta vill vi göra något mer än att bara hämta index och värden från en lista. Då är det viktigt att förstå hur vi ändrar värdet som vi hämtat och hur vi ändrar värdet som finns lagrat i listan.

Kodexempel: förändra data i en lista

cities = ["Göteborg", "Alingsås", "Borås"]
for index, value in enumerate(cities):
    if value == "Borås":
        cities[index] = "Borås i listan"
        value = "Borås i loopen"
    print(index, value)

print(cities)

Utskrift

0 Göteborg
1 Alingsås
2 Borås i loopen
['Göteborg', 'Alingsås', 'Borås i listan']

4.3.1.4 Skriv ut del av list

Ibland kanske vi inte vill skriva ut hela listan utan bara en del.

Kodexempel: skriv ut list

resultat = [12, 19, 22, 4, 0]

print(resultat[0:3])    # Skriv ut de tre första elementens värden, starta på index 0, gå mot index 3.
print(resultat[-1])     # Skriv ut det sista värdet i listan
print(resultat[::-1])   # Vänd listan

Utskrift

[12, 19, 22]
0
[0, 4, 22, 19, 12]

När vi anger [-1] för det sista indexet så frågar vi efter ett specifikt värde och därför så returneras ingen lista utan endast ett värde.

4.3.1.5 Lägg till och ta bort

Hittills har vi bara kikat på listor som får alla sina värden när listan skapas. Det går bra att lägga till, eller ta bort, element efter att listan är skapad. Här kommer ett exempel på både hur man lägger till och tar bort ett element.

Kodexempel: lägg till och ta bort element i en list

cities = ["Göteborg", "Alingsås", "Borås"]
print(cities)

# append lägger till ett element sist i vår list
cities.append("Vårgårda")
print(cities)

# insert lägger till ett element på den plats vi vill i listan.
# Angivet index är där vi petar in vårt element
cities.insert(1, "Mölnlycke")
print(cities)

# Vi kan fråga efter index om vi känner till värdet
index_borås = cities.index("Borås")
cities.pop(index_borås)     # pop tar bort det index som anges
print(cities)

Utskrift

['Göteborg', 'Alingsås', 'Borås']
['Göteborg', 'Alingsås', 'Borås', 'Vårgårda']
['Göteborg', 'Mölnlycke', 'Alingsås', 'Borås', 'Vårgårda']
['Göteborg', 'Mölnlycke', 'Alingsås', 'Vårgårda']

Om vi skall kunna lägga till element från inmatning eller på något annat sätt så behöver vi kunna deklarera en variabel som list även om den är tom.

Kodexempel: deklarera en tom list

cities = []
print(cities)

cities.append("Alingsås")
print(cities)

Utskrift

[]
['Alingsås']

4.3.1.6 Funktioner

Python är synnerligen välbyggt för att jobba med datahantering och listor, därför finns det en hel mängd inbyggda funktioner.

Kodexempel: funktioner för list

resultat = [12, 19, 22, 4, 19, 13, 21, 18]

# Maxvärdet i list
print(max(resultat))

# Minvärdet i list
print(min(resultat))

# Summan av alla värden
print(sum(resultat))

# Antal element i vår list
print(len(resultat))

# Sortera vår list
resultat.sort()
print(resultat)

# Sorterar listan omvänt
resultat.sort(reverse=True)
print(resultat)

# Antal element med ett visst värde
print(resultat.count(19))

# Tömmer list
resultat.clear()
print(resultat)

Utskrift

22
4
128
8
[4, 12, 13, 18, 19, 19, 21, 22]
[22, 21, 19, 19, 18, 13, 12, 4]
2
[]

Uppgift: m04u08

Fyll en lista med heltal tills användaren matar in 0, då stoppas inmatningen. Skriv sedan ut summan av alla tal i listan, leta efter högsta och lägsta talet. Detta skall beräknas! Skriv sedan ut det du har beräknat och jämför med inbyggd funktion.

Tycker du att denna uppgift är svår, eller har svårt att komma igång med, så har jag delat upp den i två delar, lösningen skall bli den samma när du är klar.

Första delen

Skapa en lista med 5 heltal. Loopa igenom denna lista och beräkna summan av alla tal samt ta fram lägsta och högsta värdet. Detta skall beräknas! Skriv sedan ut det du har beräknat och jämför med inbyggd funktion.

Hjälp [klicka för att visa]

Att ge dina variabler min och max var sitt startvärde kan man göra på olika sätt. I vissa programmeringsspråk så finns det ett tydligt min och maxvärde för en viss datatyp men eftersom python automatiskt gör om en int till en long (longint) ifall värdet blir större än sitt max, eller mindre än sitt min-värde, så går det inte att använda denna tekniken.

Det säkraste sättet är att sätta första talet i listan till min- och max-värdet när vi börjar så att vi har korrekta värden att utgå ifrån.

Tips

Det är inte så dumt att skapa en pseudokod först för att planera din lösning innan du kodar den.

Andra delen

Låt nu användaren mata in tal till din lista, ta bort de tal du skapat tidigare, tills användaren matar in talet 0, då är användaren klar med inmatningen.

Se till att alla beräkningar från a-delen fortfarande fungerar.

Hjälp [klicka för att visa]

Skapa lämplig loop som avbryts på lämpligt sätt när användaren matar in talet 0. Detta värde (0) skall inte lagras i listan.

Uppgift: m04u09

Äntligen dags att ta fram tärningen och göra en sådan övning. Fråga användaren om hur många tärningsslag hen vill göra. Vi använder en vanlig tärning med värden 1-6. Simulera sedan dessa slag och lagra dem i en lista. Skriv sedan ut hur många slag det blev av varje värde, skriv ut detta på ett snyggt sätt.

Kodexempel: Slumptal

# Importera randint som gör att vi slumpa heltal
from random import randint
# Skriv ut ett slumpat tal mellan 1 och 100
print(randint(1, 100))

Utskrift

Slumpat tal mellan 1 och 100: 12

4.3.2 Tuple

Genomgång [klicka för att visa]

Denna filmen är ingen ren genomgång av det som står i detta avsnitt om Tuple utan är mer byggd som exempel och förklaring på vad en Tuple är och hur den kan användas. Använd gärna filmen ihop med det som är skriveti avsnittet.

Tuple är nästa typ av lista som vi skall kika på. Det som är speciellt med en Tuple är att den får sina värden när den skapas och sedan kan den inte ändras på något sätt. Försöker vi ge ett element ett nytt värde så kommer du få error av typen;

Error

TypeError: 'tuple' object does not support item assignment

4.3.2.1 Skapa en tuple

Skillnaden på att skapa en tuple istället för en lista är att när vi skapar en tuple så skall den skapas med parentes istället för klammer.

Kodexempel: skapa tuple

weekdays = ("måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag", "söndag")

4.3.2.2 Skriva ut hela eller delar

Att skriva ut en tuple sker på samma sätt som med en list.

Kodexempel: skapa tuple

weekdays = ("måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag", "söndag")
print(weekdays)        # Hela tupeln
print(weekdays[0])     # Tupeln med index 0 (position 1)
print("\nEn dag på varje rad")
for w in weekdays:
    print(w)

Utskrift

('måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag', 'söndag')
måndag

En dag på varje rad
måndag
tisdag
onsdag
torsdag
fredag
lördag
söndag

4.3.2.3 Funktioner

Några funktioner som kan användas när vi jobbar med en tuple.

Kodexempel: skapa tuple

weekdays = ("måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag", "söndag")

# Hur många element det finns med ett visst värde
print(weekdays.count("tisdag"))

# Vilket index ett visst värde har
print(weekdays.index("tisdag"))

# storleken på en tuple
print(len(weekdays))

# ta bort en tuple
del weekdays

# Det går nu inte att skriva ut innehållet i vår tuple,
# den är helt borttagen och inte tömd som en list
# Istället får vi ett error "NameError: name 'weekdays' is not defined"
# print(weekdays)

Utskrift

1
1
7

Uppgift

Till denna del finns det ingen uppgift, allt du kan göra med en tuple kan du göra med en list, däremot kan det finnas tillfälle då den är användbar. Kanske skulle du kunna lagra de olika alternativen om du gör ett barn- eller Bamseyatzy. Låta en tuple hålla alla alternativa värden som färger eller figurer.

4.3.3 Set

Genomgång [klicka för att visa]

Denna filmen är ingen ren genomgång av det som står i detta avsnitt om Set utan är mer byggd som exempel och förklaring på vad en Set är och hur den kan användas. Använd gärna filmen ihop med det som är skriveti avsnittet.

Set är den tredje listtypen som vi pratar om. Det som är speciellt med den är att det inte får finnas dubbletter och att listan är osorterad (det är dock en sanning med modifikation, matar du in tal så sorteras den, men inte med strängar). Eftersom det inte finns några unika index i denna lista så kan vi inte skriva ut ett specifikt element ur vårt set. Kika på exemplet för att förstå hur det fungerar.

Kodexempel: set

orter = {"Vårgårda", "Alingsås", "Göteborg", "Lerum"}
print(orter)           # slumpvis utskrift, eftersom sets är osorterad
print(len(orter))      # Hur många orter finns i set

# Kolla om ett värde finns i vårt set
if("Alingsås" in orter):
    print("Ja, Alingsås finns i vårt set")

tomt_set = set()        # Skapar ett tomt set
tal = {4, 3, 1}         # Skapar ett set
print(tal)

tal.add(2)              # Lägger till värdet 2
print(tal)

# Lägger till värdet 2 igen, denna lagras inte eftersom talet 2 redan finns
tal.add(2)

for t in tal:           # Utskrift mha for-loopen
    print(t)

tal.remove(2)           # Ta bort talet 2, ger error om 2 inte finns
tal.discard(2)          # Tar också bort talet 2, ger inget error om det ej finns
print(tal)

tal.clear()             # Tar bort allt innehåll i vårt set
print(tal)

del tal                 # Tar bort set

# Kan inte skriva ut ett borttaget set (NameError: name 'tal' is not defined)
# print(tal)

Jag visar exempel på vad man kan göra med ett set i detta fallet men flera koder fungerar även på andra listtyper som tex if("Alingsås" in orter) vilket är användbart om vi skall kolla om ett värde skall finnas, eller inte får finnas.

Utskrift

{'Göteborg', 'Lerum', 'Vårgårda', 'Alingsås'}
4
Ja, Alingsås finns i vårt set
{1, 3, 4}
{1, 2, 3, 4}
1
2
3
4
{1, 3, 4}
set()

Så funkar ett set, fokus här är att inte få dubbletter och att det inte är viktigt i vilken ordning saker skapas. Skulle kunna användas för att kolla mailadresser, användarnamn eller andra saker som behöver vara unika.

Kodexempel: set, ett praktiskt användningsområde

# En lista med ett antal värden
l1 = [1, 6, 2, 3, 2, 5, 2, 1, 3, 1, 4, 5, 1, 4, 5, 6]
print(f"Antal tal: {len(l1)}, lista: {l1}")

# Gör om till ett set
s1 = set(l1)
print(f"Antal tal: {len(s1)}, set: {s1}")

# Gör om till lista
l2 = list(s1)
print(f"Antal tal: {len(l2)}, lista: {l2}")

Här använder jag set för att få fram unika siffor i min lista.

Utskrift

Antal tal: 16, lista: [1, 6, 2, 3, 2, 5, 2, 1, 3, 1, 4, 5, 1, 4, 5, 6]
Antal tal: 6, set: {1, 2, 3, 4, 5, 6}
Antal tal: 6, lista: [1, 2, 3, 4, 5, 6]

Uppgift: m04u10

Låt användaren mata in ett antal orter. Om orten redan finns lagrad så skall orten inte lagras igen. Skriv sedan ut samtliga orter, i bokstavsordning, som användaren matat in och hur många inmatningar användaren har gjort. Matar man in Alingsås två ggr så skall det räknas som två inmatningar, även om Alingsås endast lagras en gång.

Uppgift: m04u10 - unika sporter

Här kommer en uppgift som är ett alternativ till m04u10 som kan användas för att på egen hand träna på att lösa en uppgift som liknar m04u10 om vi har kodat m04u10 tillsammans.

Du ska skapa ett program där användaren matar in namn på olika sporter. Inmatningen fortsätter tills användaren matar in en tom rad (bara trycker Enter) för att avsluta.

  • Spara alla inmatningar i en lista i den ordning de matas in.
  • Använd också ett set för att hålla koll på alla unika sporter.
  • Varje gång användaren matar in en sport som redan finns i set:et (dvs. som redan har matats in tidigare), ska programmet ge användaren en kort kommentar, t.ex. "Den sporten finns redan med!".
  • När inmatningen är klar (användaren trycker Enter utan att skriva något):
    • Skriv ut alla unika sporter i bokstavsordning.
    • Skriv ut det totala antalet inmatningar (dvs längden på listan).
    • Skriv också ut hur många unika sporter som matades in (dvs längden på set:et).

Exempel på körning

Mata in sporter (tryck Enter för att avsluta):
> Fotboll
> Handboll
> Fotboll
"Den sporten finns redan med!"
> Ishockey
> Handboll
"Den sporten finns redan med!"
>
 
Unika sporter i bokstavsordning:
Fotboll
Handboll
Ishockey
Totalt antal inmatningar: 5
Antal unika sporter: 3

4.3.4 Dictionary

Genomgång [klicka för att visa]

Denna filmen är ingen ren genomgång av det som står i detta avsnitt om Dictionary utan är mer byggd som exempel och förklaring på vad en Dictionary är och hur den kan användas. Använd gärna filmen ihop med det som är skriveti avsnittet.

Dictionary har en stark koppling mellan index, som du själv sätter, och det värde som är kopplat till index. Detta är en lämplig konstruktion för olika typer av uppslag.

Kodexempel: dictionary

points = {'A':20, 'B':17.5, 'C':15, 'D':12.5, 'E':10}
grade = input("Vilket betyg har du fått på kursen? ")
print(f"Du har angivit betyget {grade} som räknas om till poängen {points[grade]}")

# Nu kan vi lägga till F
points['F'] = 0

# Skriv ut hela dictionary, med både index och värde
print("\nOmvandlingslista")
for key, value in points.items():
    print(f"Betyget {key} ger {value:3.1f} poäng")

# Skriv ut endast värde
print("\nAlla värden")
for value in points.values():
  print(value)

# Skriv ut endast index
print("\nAlla index")
for key in points.keys():
  print(key)

# Ta bort ett element
points.pop('A')
# del points['A']   # Funkar på samma sätt

points.clear()      # Tömmer dictionary
print(points)       # Skriver ut tomt

del points          # Tar bort hela dictionary
# print(points)     # Ger error eftersom dictionary är borttaget

Utskrift

Vilket betyg har du fått på kursen? A
Du har angivit betyget A som räknas om till poängen 20
 
Omvandlingslista
Betyget A ger 20.0 poäng
Betyget B ger 17.5 poäng
Betyget C ger 15.0 poäng
Betyget D ger 12.5 poäng
Betyget E ger 10.0 poäng
Betyget F ger 0.0 poäng
 
Alla värden
20
17.5
15
12.5
10
0
 
Alla index
A
B
C
D
E
F
 
{}

Kodexempel: dictionary lagras i en lista

l_users = []                            # Listan där alla dict skall lagras

while True:
    print("\nNu skall du mata in en ny användare, avbryt inmatning genom att mata in tom sträng.")
    user = input("Mata in användarnamn: ")
    if len(user) < 1:                   # Om tom inmatning...
        break                           # ... avbryt inmatning
    pwd = input("Mata in lösenord: ")
    if len(pwd) < 1:
        break
    d = {'user': user, 'password': pwd}
    l_users.append(d)                   # Lägg till dict i listan

print("\nDu har avbrutit inmatningen.")
print(f"Här är listan med alla användare: {l_users}")

Utskrift

Nu skall du mata in en ny användare, avbryt inmatning genom att mata in tom sträng.
Mata in användarnamn: Anna
Mata in lösenord: qwerty
 
Nu skall du mata in en ny användare, avbryt inmatning genom att mata in tom sträng.
Mata in användarnamn: Bosse
Mata in lösenord: abc123
 
Nu skall du mata in en ny användare, avbryt inmatning genom att mata in tom sträng.
Mata in användarnamn: Cilla
Mata in lösenord: 12345678
 
Nu skall du mata in en ny användare, avbryt inmatning genom att mata in tom sträng.
Mata in användarnamn: 
 
Du har avbrutit inmatningen.
Här är listan med alla användare: [{'user': 'Anna', 'password': 'qwerty'}, {'user': 'Bosse', 'password': 'abc123'}, {'user': 'Cilla', 'password': '12345678'}]

Uppgift: m04u11

  • Låt användaren mata in ett antal personers namn och deras telefonnummer.
  • För varje person skapar du en ny nyckel i ett dictionary (t.ex. telefonbok) där namnet är nyckeln och telefonnumret är värdet.
  • När användaren är klar (t.ex. genom att mata in en tom rad som namn):
    • Skriv ut alla poster i telefonboken i bokstavsordning efter namn (nyckel).
    • Låt användaren sedan mata in ett namn, och om namnet finns i telefonboken, skriv ut telefonnumret.
      • Om namnet inte finns i telefonboken, skriv ut ett meddelande om att personen saknas.

Utskriftsexempel

Mata in namn (tryck Enter för att avsluta):
> Anna
Ange telefonnummer för Anna:
> 0701234567
> Kalle
Ange telefonnummer för Kalle:
> 0729876543
> Lisa
Ange telefonnummer för Lisa:
> 0731122334
>
 
Telefonbok (i bokstavsordning):
Anna: 0701234567
Kalle: 0729876543
Lisa: 0731122334
 
Skriv in ett namn för att få fram telefonnummer:
> Kalle
Telefonnummer: 0729876543

Uppgift: m04u12 (svårare)

Mata in kurser och betyg i en lista, mha dictionary. Beräkna sedan ditt meritvärde utfrån dictionary points som finns i Kodexempel: dictionary.
Tips: Skapa dictionary för varje kurs med kopplat betyg och lägg dessa i en lista.

4.3.5 En cheat sheet på listor

OperationList (lista)Set (mängd)Tuple (tupel)Dictionary (ordlista)
Skapa en tom listamylist = []myset = set()mytuple = ()mydict = {}
Skapa en lista med två elementmylist = [1, 2]myset = {1, 2}mytuple = (1, 2)mydict={1:'a', 2:'b'}
Lägga till element i listamylist.append(3)myset.add(3)Inte möjligtmydict[3] = 'c'
Ta bort element ur listamylist.remove(1) eller del mylist[0]myset.remove(1) eller myset.discard(1)Inte möjligtdel mydict[1]
Uppdatera element i listanmylist[0] = 'ny'Inte direkt tillämpligtInte möjligtmydict[1] = 'ny'
Töm listamylist.clear()myset.clear()Inte möjligtmydict.clear()
Ta bort listadel mylistdel mysetdel mytupledel mydict
Skriva ut listan som den ser utprint(mylist)print(myset)print(mytuple)print(mydict)
Skriva ut ett element i listanprint(mylist[0])Inte direkt möjligtprint(mytuple[0])print(mydict[1])
Skriva ut alla element i listan genom en loopfor e in mylist: print(e)

e står för element

for e in myset: print(e)

Kom ihåg att elementen i ett set inte är i någon specifik ordning

for e in mytuple: print(e)

För att skriva ut varje nyckel-värdepar:

for k, v in mydict.items(): print(f"K: {k}, V: {v}")

Eller bara värden:

for value in mydict.values(): print(value)

Eller bara nycklarna:

for key in mydict.keys(): print(key)

4.3.6 Praktisk användning av listor

Svårare avsnitt

Detta avsnitt visar en praktisk användning av olika typer av listor. Avsnittet är en praktisk fördjupning och är svårare än de tidigare avsnitten. Detta avsnitt är främst avsett för de elever som har bra koll på listtyperna List och Dictionary och vill utmanas med fler och/eller svårare uppgifter.

I tidigare avsnitt har vi gått igenom grunderna för listor och iterationer i Python. Nu ska vi titta på hur vi kan använda dessa koncept i praktiska tillämpningar. Genom att simulera tärningskast kommer vi att utforska hur listor och dictionaries kan användas för att lagra och analysera data på ett effektivt sätt.

4.3.6.1 Tärningsslag med listor

Vi börjar med att skapa ett program som simulerar ett antal tärningskast och använder listor för att lagra resultaten. Målet är att räkna hur många gånger varje tärningsvärde förekommer och presentera detta för användaren.

Kodexempel: Statistik av tärningsslag med listor

from random import randint    # Importerar funktionalitet för slumpmässiga tal

antal_slag = 100              # Antal tärningskast som ska utföras
slag = []                     # Lista för att lagra alla tärningsslag
frekvens = [0]*6              # Lista för att räkna frekvensen av varje tärningsvärde (index 0-5)

for i in range(antal_slag):   # Loopar antal_slag gånger
    värde = randint(1, 6)     # Slår ett tärningsslag (värde mellan 1 och 6)
    slag.append(värde)        # Lägger till tärningsslaget i listan slag
    frekvens[värde - 1] += 1  # Ökar räknaren för det aktuella tärningsvärdet

# Skriver ut frekvensen av varje tärningsvärde
print("Frekvens av varje tärningsvärde:")
for i in range(6):
    print(f"Värde {i+1}: {frekvens[i]} gånger")

# Skriver ut alla tärningsslag
print("\nAlla tärningsslag:")
print(slag)
4.3.6.2.1 Förklaring av koden
  • Vi importerar randint från modulen random för att kunna generera slumpmässiga tal mellan 1 och 6.
  • Variabler
    • antal_slag: Antalet tärningskast som ska simuleras.
    • slag: En lista som lagrar resultatet av varje tärningskast.
    • frekvens: En lista med sex nollor som används för att räkna hur många gånger varje tärningsvärde förekommer.
  • Huvudloopen
    • Vi loopar antal_slag gånger och simulerar ett tärningskast varje gång.
    • Resultatet av tärningskastet lagras i värde.
    • Vi lägger till värde i listan slag.
    • Vi ökar räknaren för det aktuella tärningsvärdet i listan frekvens. Eftersom listan är nollindexerad, subtraherar vi 1 från värde för att få rätt index.
  • Utskrift
    • Vi loopar genom listan frekvens och skriver ut hur många gånger varje tärningsvärde förekom.
    • Vi skriver också ut alla tärningsslag som lagrats i listan slag.

4.3.6.2 Tärningsslag med dictionaries

Nu ska vi förbättra vårt program genom att använda en dictionary istället för listor för att räkna frekvensen av varje tärningsvärde. Dictionaries är särskilt användbara när vi vill koppla nycklar (tärningsvärden) till värden (antal gånger de förekommer).

Kodexempel: Statistik av tärningsslag med dictionarys

from random import randint    # Importerar funktionalitet för slumpmässiga tal

antal_slag = 100              # Antal tärningskast som ska utföras
slag = []                     # Lista för att lagra alla tärningsslag
frekvens = {}                 # Dictionary för att lagra frekvensen av varje tärningsvärde

for i in range(antal_slag):
    värde = randint(1, 6)     # Slår ett tärningskast (värde mellan 1 och 6)
    # Använder try / except för att uppdatera frekvensen i dictionaryn
    try:
        frekvens[värde] += 1  # Ökar räknaren för det aktuella tärningsvärdet
    except KeyError:
        frekvens[värde] = 1   # Skapar ny nyckel i dictionaryn om den inte finns

# Skriver ut hela dictionaryn
print("\nFrekvens av varje tärningsvärde:")
print(frekvens)

# Skriver ut varje tärningsvärde och dess frekvens
print("\nUtskrift av tärningsvärden och deras frekvenser:")
for nyckel in frekvens:
    print(f"Tärningsvärde {nyckel}: {frekvens[nyckel]} gånger")

# Sorterar och skriver ut tärningsvärdena i ordning
print("\nTärningsvärden sorterade efter värde:")
for nyckel, värde in sorted(frekvens.items()):
    print(f"Tärningsvärde {nyckel}: {värde} gånger")

# Sorterar och skriver ut tärningsvärdena i omvänd ordning
print("\nTärningsvärden sorterade i omvänd ordning:")
for nyckel, värde in sorted(frekvens.items(), reverse=True):
    print(f"Tärningsvärde {nyckel}: {värde} gånger")

# Sorterar baserat på frekvens och skriver ut i fallande ordning
print("\nTärningsvärden sorterade efter frekvens (högst först):")
for nyckel, värde in sorted(frekvens.items(), key=lambda x: x[1], reverse=True):
    print(f"Tärningsvärde {nyckel}: {värde} gånger")
    
# Ett alternativt sätt ifall man vill sortera först på antal och sedan värde
# -x[1] innebär fallande, x[0] innebär stigande
print("\nTärningsvärden sorterade först på frekvens och sedan på värde:")
for nyckel, värde in sorted(frekvens.items(), key=lambda x: (-x[1], x[0])):
    print(f"Tärningsvärde {nyckel}: {värde} gånger")

# Skriver ut alla tärningsslag
print("\nAlla tärningsslag:")
print(slag)
4.3.6.2.1 Förklaring av koden
  • Vi importerar randint från modulen random för att kunna generera slumpmässiga tal mellan 1 och 6.
  • Variabler
    • antal_slag: Antalet tärningskast som ska simuleras.
    • slag: En lista som lagrar resultatet av varje tärningskast.
    • frekvens: En tom dictionary som kommer att lagra frekvensen av varje tärningsvärde.
  • Huvudloopen
    • Vi loopar antal_slag gånger och simulerar ett tärningskast varje gång.
    • slag: En lista som lagrar resultatet av varje tärningskast.
    • Vi använder try / except för att hantera uppdateringen av frekvens:
      • Om tärningsvärdet redan finns som en nyckel i frekvens, ökar vi dess värde med 1.
      • Om tärningsvärdet inte finns, fångar vi KeyError och lägger till nyckeln med startvärdet 1. Ett KeyError är en mer specifik typ av Exception istället för att fånga ett allmänt error. Se avsnitt 4.3.6.2.3 för alternativa lösningar.
  • Utskrift
    • Vi skriver ut hela dictionaryn för att se frekvensen av varje tärningsvärde.
    • Vi loopar genom frekvens och skriver ut varje nyckel och dess värde.
    • Vi visar hur man kan sortera dictionaryn på olika sätt:
      • Sortera efter tärningsvärde.
      • Sortera i omvänd ordning efter tärningsvärde.
      • Sortera efter frekvens med hjälp av en lambda-funktion.
    • Vi skriver också ut alla tärningsslag som lagrats i listan slag, vilket kan vara bra att jämföra övriga resultat med.
4.3.6.2.2 Förklaring av lambda

Lambda-anropet behöver nog en särskild förklaring.

Kodexempel: lambda alternativ 1

print("\nTärningsvärden sorterade efter frekvens (högst först):")
for nyckel, värde in sorted(frekvens.items(), key=lambda x: x[1], reverse=True):
    print(f"Tärningsvärde {nyckel}: {värde} gånger")
  • frekvens.items(): Returnerar en lista med dictionaryns nyckel-värde-par som tupler.
  • sorted(): En inbyggd funktion som sorterar en iterable (datastruktur som går att loopa igenom, som listorna i detta avsnitt men också datatypen String).
  • key=: Ett argument till sorted() där vi kan ange en funktion som bestämmer sorteringsordningen.
  • lambda x: x[1]: En anonym funktion som tar ett argument x (i detta fall en tuple) och returnerar det andra elementet i tuplen (x[1]), alltså frekvensen.
  • reverse=True: Anger att sorteringen ska ske i omvänd ordning (från högsta till lägsta frekvens).

Kodexempel: lambda alternativ 2

print("\nTärningsvärden sorterade först på frekvens och sedan på värde:")
for nyckel, värde in sorted(frekvens.items(), key=lambda x: (-x[1], x[0])):
    print(f"Tärningsvärde {nyckel}: {värde} gånger")

Skillnaden i detta exempel är att vi väljer att sortera frekvensen i fallande ordning -x[1] och sedan värdena i stigande ordning x[0]. -x[1] innebär fallande, x[0] innebär stigande.

Varför är det lämpligt att använda lambda i denna situation?

  • Enkelhet: Lambda-funktionen gör det möjligt att snabbt definiera en enkel sorteringsnyckel utan att behöva skriva en separat funktion.
  • Effektivitet: Koden blir mer kompakt och lättläst.

Vi går inte dljuare i lambdafunktioner just nu men det är användbart när data skall behandlas. Kanske återkommer vi till det senare i kursen men nu har du sett det en gång iaf om du skulle stöta på det vid någon sökning på nätet.

4.3.6.2.3 Jämförelse mellan try / except,if-sats och dict.get()

Vi använde try / except för att hantera uppdateringen av frekvens i lösningen ovan. Det finns alternativa lösningar för just det vi ville göra och här går jag igenom dem.

Kodexempel: try / except

try:
    frekvens[värde] += 1
except KeyError:
    frekvens[värde] = 1

Vi försöker öka värdet för nyckeln värde med 1. Om nyckeln inte finns (vilket orsakar en KeyError), fångar vi undantaget och lägger till nyckeln med startvärdet 1.

Kodexempel: if-sats

if värde in frekvens:
    frekvens[värde] += 1
else:
    frekvens[värde] = 1

Vi kontrollerar om nyckeln värde finns i frekvens. Om den gör det, ökar vi värdet med 1. Annars lägger vi till nyckeln med startvärdet 1.

Kodexempel: dict.get()

frekvens[värde] = frekvens.get(värde, 0) + 1
  • frekvens.get(värde, 0): Försöker hämta värdet för nyckeln värde. Om nyckeln inte finns, returnerar den 0.
  • frekvens[värde] = ...: Vi ökar det hämtade värdet med 1 och tilldelar det till frekvens[värde].

Flera olika varianter för att lösa samma uppgift, det är python i ett nötskal. Använd den lösning som du gillar mest och som du kan använda i skarpt läge.

Uppgift: m04u13

En klass har just skrivit ett matematikprov, och läraren har samlat in betygen. Betygen (skala 1 till 5) för de 25 eleverna är som följer:

resultatlistan

resultat = [4, 3, 5, 2, 4, 3, 4, 5, 3, 2, 4, 5, 3, 4, 2, 4, 5, 3, 4, 2, 4, 5, 3, 4, 2]

Uppgiften är fyrdelad;

  1. Skriv ut alla elevernas betyg i den ordning de ligger i listan.
  2. Utskrift

    Alla betyg:
    4 3 5 2 4 3 4 5 3 2 4 5 3 4 2 4 5 3 4 2 4 5 3 4 2
  3. Räkna förekomster av varje betyg. TIPS: Att göra detta med en dictionary kommer underlätta nästa uppgift.
  4. Skriv ut hur många elever som har fått varje betyg. Om du har använt en dictionary så sortera betygen efter hur många elever som fick dem, från flest till färst. Använde du lista på uppgift två så skriv ut betygen i ordning från 1 till 5.
  5. Utskrift

    Betyg sorterade efter antal elever:
    Betyg 4: 9 elever
    Betyg 3: 6 elever
    Betyg 5: 5 elever
    Betyg 2: 5 elever
  6. Beräkna medelvärde och median av betygen.
  7. Utskrift

    Medelvärde: 3.56
    Median: 4

Uppgift: m04u14 (svårare)

Matematikprovet (m04u13) bestod av tre delar: Algebra, Geometri och Statistik. Varje del gav maximalt 10 poäng. Läraren har nu poängen för varje elev i varje del, organiserade som en lista av listor (en tvådimensionell lista), där varje inre lista representerar en elevs resultat:

resultatlistan

provresultat = [
    [7, 8, 6],[5, 6, 5],[9, 8, 7],[6, 5, 6],[8, 9, 8],
    [6, 7, 5],[7, 8, 7],[5, 6, 4],[8, 7, 8],[6, 5, 6],
    [7, 8, 7],[5, 6, 5],[8, 9, 8],[6, 7, 6],[7, 8, 7],
    [5, 6, 5],[8, 9, 8],[6, 7, 6],[7, 8, 7],[5, 6, 5],
    [8, 9, 8],[6, 7, 6],[7, 8, 7],[5, 6, 5],[8, 9, 8]
]

Uppgiften är fyrdelad;

  1. Skriv ut varje elevs poäng i de tre delarna samt totalpoängen.
  2. Utskrift

    Elevernas resultat:
    Elev 1: Algebra 7, Geometri 8, Statistik 6, Total 21
    Elev 2: Algebra 5, Geometri 6, Statistik 5, Total 16
    Elev 3: Algebra 9, Geometri 8, Statistik 7, Total 24
    osv...
  3. Beräkna och skriv ut genomsnittspoängen för Algebra, Geometri och Statistik.
  4. Utskrift

    Genomsnittspoäng:
    Algebra: 6.60
    Geometri: 7.28
    Statistik: 6.40
  5. Hitta och skriv ut den högsta och lägsta poängen som uppnåddes i varje del.
  6. Utskrift

    Högsta och lägsta poäng per del:
    Algebra: Högsta 9, Lägsta 5
    Geometri: Högsta 9, Lägsta 5
    Statistik: Högsta 8, Lägsta 4
  7. Sortera eleverna efter totalpoäng (från högsta till lägsta) och skriv ut resultaten.
  8. Utskrift

    Elev 5: Total 25, Algebra 8, Geometri 9, Statistik 8
    Elev 13: Total 25, Algebra 8, Geometri 9, Statistik 8
    Elev 17: Total 25, Algebra 8, Geometri 9, Statistik 8
    Elev 21: Total 25, Algebra 8, Geometri 9, Statistik 8
    Elev 25: Total 25, Algebra 8, Geometri 9, Statistik 8
    Elev 3: Total 24, Algebra 9, Geometri 8, Statistik 7
    osv...

4.4 Slutuppgift på momentet

Två stycken diagnoser, teoretisk och praktisk, avrundar momentet.

Vill du förbereda dig inför slutuppgifterna så jobba med uppgifterna i detta moment, kolla på vad du fick som feedback på tidigare inlämningsuppgifter och kika i extramaterialet om du vill träna mer.