4. Moment04 - Iterationer och listor

Info

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

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, bestämt slutvärde

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. 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.

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.

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.

4.1.1 Nästlade iterationer

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 iterationer, det går att nästla dem i flera led och det går också att nästla iterationer i andra selektioner osv.

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 ("\nVi loopar från {} till {}.".format(start, 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 ("När i är {} så är totalsumman {}".format(i, summa))
# else som tillhör loopen och körs när loopen har körts färdigt
else:
    print ("När vi loopat färdigt så är summan {}".format(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

Jag har tidigare nämnt att iteration 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 ("Klockan är {}, ".format(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.

4.2 while-loopen

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 ("När vi har loopat klart så har tal värdet {}".format(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.

4.2.1 Continue

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.

4.2.2 Break

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

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.3 Aktivitetsdiagram och pseduokod för loopar

AktivitetsdiagramI förra momentet lärde vi oss att skriva pseudokod och aktivitetsdiagram 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

Som du ser är den lik aktivitetsdiagrammet, men man skulle också kunna skriva den på ett mer generellt sätt så att varje utvecklare själv kan välja vilken typ av loop som skall/kan användas. Då kan det se 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 finns inget rätt eller fel även om du i det första exemplet troligtvis styrs till att använda while-loopen och i det andra själv får välja vilken iteration du vill använda för att lösa uppgiften.

Avancerade algoritmer med flera eller djupa iterationer känns ofta lättare att följa med ett aktivitetsdiagram än med pseudokod.

Uppgift: m04u06 (svårare)

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 aktivitetsdiagram eller pseudokod.

4.2.4 Felhantering, körtidsfel

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 ("Det korrekt inmatade talet är {}".format(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.

4.3 Listtyper

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

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.

Kodexempel: skriv ut list individuellt

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

# Loopar igenom resultat med en for-loop
for r in 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 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]

# Skriv ut de tre första elementens värden
print (resultat[0:3])

Utskrift

[12, 19, 22]

4.3.1.4 Enskilt element

Eftersom det går att ropa på ett enskilt element så bör de ha något som identifierar dem. Detta kallas för ett index och det kan vi använda om vi vill skriva ut ett särskilt värde.

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.

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)

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

Utskrift

['Göteborg', 'Alingsås', 'Borås']
['Göteborg', 'Alingsås', 'Borås', 'Vårgårda']
['Göteborg', '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)

# 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]
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: 35

Uppgift: Yatzy (Extrauppgift)

Här kommer en extrauppgift som du har möjlighet att bygga på hur långt du vill. Yatzy är ett klassiskt spel med fem tärningar, klassisk tärning 1-6, där det gäller att samla poäng genom att samla på olika serier av tärningsslag.

Börja med att att skapa fem slumpade tärningar i en lista. Skriv sedan ut din hand på valfritt sätt.

Första uppgiften är att kolla om det finns minst ett par bland dina fem tärningar. Använd gärna aktivitetsdiagram och/eller pseudokod för att planera hur du skall lösa detta.

  • Kan du visa vilket värde som blivit yatzy (1:or, 2:or osv..).
  • Kan du se om det är flera par?
  • Kan du se om det blivit någon triss?

Alla som har spelat yatzy vet att det är en hel del olika typer av slag som kan ge olika antal poäng. Att bygga upp hela detta spelet tar en stund och är väl omfattande för denna kursen. Hur hittar vi då en förenklad version av yatzy? Vi går naturligtvis till barnspelen och kikar på hur barn- och bamse-yatzy fungerar. Utifrån dessa regler så är det enklare att bygga fullt fungerande varianter av yatzy.

Barnyatzy [klicka för regler]

Bamseyatzy [klicka för regler]

4.3.2 Tuple

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

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")

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)

Utskrift

{'Alingsås', 'Lerum', 'Göteborg', 'Vårgårda'}
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.

Uppgift

Till denna del finns det ingen uppgift, det viktigaste är att du vet om att set finns och att väljer denna typ där det är lämpligt.

4.3.4 Dictionary

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 ("Du har angivit betyget {} som räknas om till poängen {}".format(grade, points[grade]))

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

print ("\nOmvandlingslista")
for key, value in points.items():
    print ("Betyget {} ger {:3.1f} poäng".format(key, value))

# 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
{}

Uppgift

Till denna del finns det ingen uppgift, det viktigaste är att du vet om att dictionary finns och att väljer denna typ där det är lämpligt.

4.4 Inlämningsuppgift

Denna uppgift byggs på i flera delar. Du löser så många delar du kan och lämnar in den sista fungerande lösningen. I denna övning kommer jag testa dig på tekniker från detta och tidigare moment men framförallt testas du på problemlösning. Ta hand om en del i taget, klura ut vad jag vill att du gör, dela upp uppgiften i mindre delar och när du är helt klar med den delen så går du vidare till nästa. Du kommer inte vinna på att kika på flera delar åt gången. I de tidigare delarna så får du lite extra hjälp att komma igång medan de senare delarna kräver en del egen problemlösning för att få det att fungera. I varje del så får du se hur min utskrift ser ut när jag har löst programmet, du måste inte härma mig men det kan vara en vägledning för att du skall förstå uppgiften.

I uppgift a ligger fokus på iteration och selektion, i uppgift b ligger fokus på fler iterationer och även listor. Jag vill att du klarar av dessa två innan inlämning för att visa på kunskaper inom de delar som ingår i momentet.

Inlämningsinstruktioner

Innan du lämnar in uppgiften kolla att följande saker är gjorda;

  • Filen med källkod har rätt namn, klass_namn_moment04.py.
  • Applikationen körs utan error. Koden är rensad från testdata och ser ok ut att lämna in.
  • Källkoden är kommenterad. För din egen del se till att du kommenterar koden eftersom den hela tiden byggs på.
  • Skapa ett huvud i källkoden där du som en kommentar skriver ditt namn och klass, vilken uppgift som du har löst och sedan en kort utvärdering av lösningen/ditt arbete. Jag är extra intresserad över hur du har tänkt när du fått ta olika beslut. I denna uppgift så finns det i del b-e en fråga som jag vill att du besvarar. Gör detta i kodhuvudet.
  • Är du godkänd på aktivitetsdiagram och pseudokod sedan tidigare så behöver du inte göra det på denna uppgiften. Har du inte lämnat in sedan tidigare, eller inte är godkänd, så är det lämpligt att skapa sådana för någon vald algoritm. Tala om vilken algoritm du har avgränsat och lämnat in lösning för. Lämna in i textformat, bildformat eller pdf och namnge filen med ditt namn och momentets namn.

Exempel på kodhuvud

# Anders Andersson, 18TEx
# Moment04, uppgift d
# Det var en utmanade uppgift och jag klarade inte av sista tillägget.
# Det som var mest utmanande var hur jag skulle konvertera det som matades in...
# ....

Inlämningsuppgift moment04

Uppgiften är att bygga en applikation som beräknar olika saker kring en rektangel och ett rätblock. Den matematiska delen skall inte vara svår utan fokus ligger på problemlösning, iterationer och användning av listor.

Läs och lös en uppgift i taget.

Uppgift a [klicka för att visa]

Be användaren ange rektangelns två sidor, vi använder endast heltal. Skriv ut arean på rektangeln och skriv också ut ett meddelande ifall rektangeln är en kvadrat. Slutligen skall du på lämpligt sätt beräkna och skriva ut volymen på rätblock med den angivna rektangeln som bas och alla heltalshöjder mellan 1 och 10. Enhet behöver du inte ange, vill du göra det så går le, ae och ve bra (längdenhet, areaenhet, volymenhet).

Hjälp [klicka för att visa]

Här får du hjälp i form av pseudokod. Använd den gärna som exempel för kommentarer och skriv koden under.

# Be användaren mata in rektangelns två sidor
# Beräkna och skriv ut arean på rektangeln
# Om bägge sidorna är lika långa...
  # ... tala om att det är en kvadrat
# Loopa höjden från 1 till 10
  # Beräkna volymen och skriv ut den

Utskrift

Så här kan resultatet se ut när jag kör mitt program. Du måste inte göra exakt likadant.

Denna applikation gör ett antal beräkningar på en rektangel/rätblock.
Ange rektangelns ena sida: 5
Ange rektangelns andra sida: 5

Rektangeln har sidorna 5 och 5 vilket gör att arean är 25
Eftersom bägge sidorna är lika långa så är denna rektangel en kvadrat.

Höjden | Volymen
-----------------
     1 |      25
     2 |      50
     3 |      75
     4 |     100
     5 |     125
     6 |     150
     7 |     175
     8 |     200
     9 |     225
    10 |     250

Uppgift b [klicka för att visa]

När du har ett fungerande program från uppgift a så vill jag att detta program skall köras om och om igen tills användaren på något sätt, som du väljer, inte vill köra fler beräkningar.

Varje gång du har utfört en areaberäkning vill jag att du i en lista lagrar info om rektangelns sidor, area och ifall det är en kvadrat.

När användaren har valt att inte göra fler beräkningar skall alla beräkningar visas upp innan programmet avslutas.

Berätta i kodhuvudet hur du har löst den stora programloopen (den som styr hur länge användaren vill köra applikationen) och motivera ditt val.

Hjälp [klicka för att visa]

Här får du hjälp i form av pseudokod. Använd den gärna som exempel för kommentarer och skriv koden under.

# Skapa en loop som bryter när användaren inte vill göra fler beräkningar
  # Be användaren mata in rektangelns två sidor
  # Beräkna och skriv ut arean på rektangeln samt lagra i listan
  # Om bägge sidorna är lika långa...
    # ... tala om att det är en kvadrat och skriv detta i listan
  # Loopa höjden från 1 till 10
    # Beräkna volymen och skriv ut den
  # Fråga användaren om hen vill göra fler beräkningar
    # Om inte avryt loopen
# Skriv ut alla beräkningar

Utskrift

Så här kan resultatet se ut när jag kör mitt program. Du måste inte göra exakt likadant.

Denna applikation gör ett antal beräkningar på en rektangel/rätblock.
Ange rektangelns ena sida: 5
Ange rektangelns andra sida: 5

Rektangeln har sidorna 5 och 5 vilket gör att arean är 25
Eftersom bägge sidorna är lika långa så är denna rektangel en kvadrat.

Höjden | Volymen
-----------------
     1 |      25
###### bortklippt ######
    10 |     250
Vill du göra en beräkning till (J/N)? J

Ange rektangelns ena sida: 6
Ange rektangelns andra sida: 4

Rektangeln har sidorna 6 och 4 vilket gör att arean är 24

Höjden | Volymen
-----------------
     1 |      24
###### bortklippt ######
    10 |     240
Vill du göra en beräkning till (J/N)? N

Rektangeln har sidorna 5 och 5 vilket gör att arean är 25, rektangeln är en kvadrat.
Rektangeln har sidorna 6 och 4 vilket gör att arean är 24

Uppgift c [klicka för att visa]

Bygg vidare på uppgift b. Denna gång skall du låta användaren mata in vilka höjder som skall visas i volymuträkningen. Om användaren matar in 5 så skall volymen för alla höjder 1-5 visas. Du skall också hjälpa användaren att göra rätt genom att;

  • Om användaren matar in något annat än ett heltal så skall användaren få chansen igen.
  • Om användaren matar in ett negativt tal skall höjden sättas till 1
  • Om användaren matar in ett större tal än 10 så skall höjden sättas till 10.

Du behöver fortfarande inte ha denna säkerhet/logik kring inmatning av rektangelns två sidor.

Berätta i kodhuvudet hur du har tagit hand om, och hjälpt, användaren med inmatningen och motivera ditt val.

Utskrift

Så här kan resultatet se ut när jag kör mitt program. Du måste inte göra exakt likadant.

Denna applikation gör ett antal beräkningar på en rektangel/rätblock.
Ange rektangelns ena sida: 5
Ange rektangelns andra sida: 5
Ange rätblockets höjd: tre
Du har gjort en felaktig inmatning, ange ett heltal
Ange rätblockets höjd: -3

Rektangeln har sidorna 5 och 5 vilket gör att arean är 25
Eftersom bägge sidorna är lika långa så är denna rektangel en kvadrat.

Höjden | Volymen
-----------------
     1 |      25
Vill du göra en beräkning till (J/N)? N
Rektangeln har sidorna 5 och 5 vilket gör att arean är 25, rektangeln är en kvadrat.

Tänk på att höjden -3 skulle sättas till 1.

Uppgift d [klicka för att visa]

Nu är det dags att bygga om applikationen en hel del, kan vara läge att spara en kopia av del c ifall du behöver backa och göra om. Ingen ny funktionalitet skall läggas till men nu vill jag att du i en, eller flera, listor lagrar rektangelns två sidor och den höjden du skall räkna upp till för varje rätblock. Se till att du får inmatningarna på det sätt som du vill. När användaren har matat in sina värden för ett önskat antal rätblock så skall alla uträkningar skrivas ut på samma sätt som förut.

Berätta i kodhuvudet hur du valt att lagra värden för sidorna och höjden samt motivera ditt val.

Utskrift

Utskrifterna kan i princip se ut på samma sätt som tidigare.

Uppgift e [klicka för att visa]

Dags för den sista delen som också är en liten blick in i nästa moment. Vi skall kika på funktioner och hur man kan skapa sina egna funktioner.

En egengjord funktion bygger man av kod som antingen är tydligt avgränsad (för beräkningar av area, omkrets, volym etc) eller för att det är en kodsnutt som återanvänds flera gånger (t.ex. kontroller för inmatning av flera tal). Inom programmeringen, och matematiken, pratar vi om en algoritm som är en begränsad uppsättning instruktioner för att lösa en uppgift. Fokus här är att lösa en uppgift, skall det utföras två uppgifter, beräkna area och omkrets, så kan/bör det skapas två funktioner.

Kodexempel: funktioner

# funktion omkrets
# inparameter: sida1 & sida2
# returvärde inget
def omkrets(s1, s2):
    print ("Omkretsen av en rektangel med sidorna {} och {} är {}"
           .format(s1, s2, 2*(s1+s2)))

# funktion omkrets_retur
# inparameter: sida1 & sida2
# returvärde: omkretsen
def omkrets_retur(s1, s2):
    return 2*(s1+s2)

sida1 = 5
sida2 = 5

# ta emot det returnerade värdet
o = omkrets_retur(sida1, sida2)

# Anropar funktionen omkrets för utskrift
omkrets(sida1, sida2)

# Anropar funktionen omkrets_retur i utskriften
print ("Omkretsen av en rektangel med sidorna {} och {} är {}"
       .format(sida1, sida2, omkrets_retur(sida1, sida2)))

Infoga en eller flera funktioner i din applikation på lämplig algoritm, några exempel finns i presentationstexten för funktioner.

Berätta i kodhuvudet hur du valt att använda funktioner hur det har fungerat.

Innan inlämning, se till att du har fungerande kod, att du har följt inlämningsinstruktionerna och att du har döpt alla filer på rätt sätt.