LES 2: Werken met lijsten, de while loop en functiedefinities#

In dit hoofdstuk leer je wat lijsten zijn, en hoe je zogeheten loops gebruikt. Je hebt al kennisgemaakt met de for-loop, in dit hoofdstuk komt ook de while loop voor.

#lijsten Het begrip lijsten ben je misschien al bij natuurkunde tegengekomen. Het is niet anders dan een reeks getallen (of andere type variabelen) die je opslaat. Je kan het voorstellen als een tabel. Een ander woord in het engels is array.

De lijst getallen 1 t/m 10 wordt weergegeven als [1, 2, 3, 4, 5, 6, 7, 8, 9 10]. Deze lijst kan worden opgeslagen zoals je dat ook met strings of getallen doet, en met commando print() kan je de inhoud op het scherm toveren.

Hieronder een voorbeeld

lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(lijstje)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Merk op dat je de inhoud van lijsten dus scheid met een komma. Dit is dus ook de reden dat als je een getal met een komma noteert een foutmelding krijgt. Je ziet in de foutmelding typeerror staan, en het woord tuple (dat zijn objecten geschreiden door een komma)

a = 1,4
b= 3,6
print(a*b)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[2], line 3
      1 a = 1,4
      2 b= 3,6
----> 3 print(a*b)

TypeError: can't multiply sequence by non-int of type 'tuple'

Een andere manier om deze lijst te maken is met list(range(1,11)), zeker als je grotere lijsten wil is dit handiger. range(1,11) heeft als beginwaarde 1 en eindwaarde 10, eentje minder dus. het is dus van begin TOT eind, niet TOT EN MET

lijstje = list(range(1,11))
print(lijstje)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Hoe kan je lijsten ‘lezen’ en bewerken.#

Stel ik wil het getal 3 oproepen in lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. Dat is hier het derde getal, echter beginnen we met python met 0 te tellen. De plek in een lijst wordt aangeduid met ‘index’. De ‘index’ van het getal 3 in lijstje is dus 2. Dat roep je aan met rechte haken [ ]. Zie hieronder het voorbeeld.

lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(lijstje[2])  # met [2] wordt van de inhoud van lijstje de 3e item opgevraagd, dat printen we dan
 
3

Wil je de laatste item hebben van je lijst, maar geen zin om te tellen? Dan kan je ook ‘achteruit’ tellen. Zo roep je met print(lijstje[-1]) het getal 10 op. Bedenk wat de output zou zijn van print(lijstje[-4]) en controleer dat hieronder.

lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(lijstje[-1])
10

Let op dat je niet een index opvraagt die buiten de zogeheten ‘range’ van je lijst zit. Probeer maar, je krijgt dan Indexerror: list index out of range

lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(lijstje[15])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[16], line 2
      1 lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
----> 2 print(lijstje[15])

IndexError: list index out of range

Je kan als volgt dingen TOEVOEGEN aan een lijst: lijstje.append(11). Het .append() gedeelte is een zogeheten methode uit een zogeheten module, dat bij lijsten gebruikt wordt. Je zal deze notatie later vaker tegenkomen en komen we later nog eens op terug. De logica achter het woord ‘append’ is gewoon ‘appendix’, toevoeging.

lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
lijstje.append(11)
print(lijstje)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

Wil je een getal IN een lijstje toevoegen, gebruik je lijstje.insert(). Wil je bijvoorbeeld de waarde 5.5 toevoegen tussen de 5 en een 6, moet je lijstje.insert(5, 5.5) aanroepen. De logica is dat je zoekt naar index van het getal 6, dat is 5 (je begint bij 0 te tellen…) en op die plek de 5.5 zet, immers na de waarde 5 met index 4, en alle andere waarden dan dus een index opschuift.

Het aantal items in een lijst (de lengte) kan je aanroepen met len(). Check hieronder dat er dus nu 11 items zijn in de nieuwe lijst nadat 5.5 is toegevoegd.

lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
lijstje.insert(5, 5.5)
print(lijstje)
print(len(lijstje))
[1, 2, 3, 4, 5, 5.5, 6, 7, 8, 9, 10]
11

Wil je een item vervangen, bijvoorbeeld het getal 6 door 16, kan dat met lijstje[5]=16

lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
lijstje[5]=16
print(lijstje)
[1, 2, 3, 4, 5, 16, 7, 8, 9, 10]

WEET je echter niet welke index een bepaalde warde heeft (want je lijst is te groot om te tellen). Kan je met lijstje.index() de index van een waarde vinden, dat opslaan als variabele, en die variabele weer oproepen in lijstje[]. Om deze paragraaf over lijsten een beetje af te ronden, kan je natuurlijk ook andere soorten variabelen opslaan in een lijst. Hieronder vervangen we het getal 6 door de string ‘paard’.

lijstje = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
index_van_6 = lijstje.index(6)
lijstje[index_van_6]='paard'
print(lijstje)
[1, 2, 3, 4, 5, 'paard', 7, 8, 9, 10]

OPDRACHT Genereer een lijst van even getallen onder de 100. Hieronder een begin. Herinner dat een getal even is als je het kan delen door 2, in python doe je dat met %.

lijst = list(range(1,101))    #dit genereert een lijst van 1 tot en met 100
evenlijst = []                #dit wordt het lijstje van even getallen
for getal in lijst:
    if(....):   #noteer hier wat er getest moet worden
        ....    #noteer hier hoe je dan de evenlijst vult

print(evenlijst)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]

Lijsten toegepast, en introductie while-loop.#

Nu gaan we eens wiskundeproblemen oplossen met gebruik van lijsten. In deze oefening gaan we een lijst maken van de eerste 100 ONEVEN getallen. Dat gaan we natuurlijk niet met de hand doen. Een manier (er zijn meerdere manieren natuurlijk) is als volgt. We maken een lijst, genaamd onevengetallenlijst, en we beginnen met een zogeten lege lijst. onevengetallenlijst = []. Vervolgens gaan we net zo lang een getal toevoegen met .append() tot de lengte van de lijs len(onevengetallenlijst) gelijk is aan 100.

Deze laatste zin kan je afdoen in python met de zogeheten while loop. Zolang aan een bepaalde conditie nog is voldaan, doen we het volgende stukje code steeds opnieuw.

Dan willen we een lijst getallen afgaan en checken of deze oneven is. We moeten dan met een eerste getal beginnen, en we weten al wat het eerste oneven getal is, namelijk 1. start dan dus met een variabele en sla daar de waarde 1 op, getal = 1. Dan starten we de while loop: Zolang het aantal oneven getallen kleiner is dan 100, doe het volgende: Als het getal oneven is, slaan we dit getal op in de lijst. Daarna hoegen we de waarde met 1 op.

Het checken van of een getal oneven is, vraagt een extra denkstap. Een getal is oneven als deze niet deelbaar is door 2. Dit is hetzelfde zeggen als als je deelt door 2, je een rest 1 krijgt. Dit is in een ander hoofdstuk al aan de orde geweest: getal%2. Dit heet modulo rekenen, en de procent geeft de rest door deling met 2. ALs hier 1 uit komt, is het getal dus oneven geweest. Dat checken gebeurd in de regel met if getal%2 == 1:. Let op de twee =-tekens, dit is het commando om links en rechts van het = teken met elkaar te vergelijken: 5%2 is namelijk gelijk aan 1, en we checken dan of dit daadwerkelijk gelijk is aan 1. 6%2 is gelijk aan 0, dus het getal 6 willen we niet opslaan in het lijstje.

In de laatste regel in de while loop staat getal = getal+1. We hebben namelijk een getal gecheckt of deze deelbaar is door 2 en rest 1 geeft, en willen deze nu ophogen. Let op de inspringing! Deze ophoging moet ‘binnen’ de while loop blijven, maar buiten de if-statement.

Probeer dan nu het onderstaande stukje te begrijpen. Controleer of je inderdaad 1 tot 199 hebt en dat dit 100 oneven getallen zijn, het is een variatie van de vorige opgave

onevengetallenlijst = []
getal = 1
while len(onevengetallenlijst) < 100:
    if getal%2 == 1:
        onevengetallenlijst.append(getal)
    getal = getal + 1

print(onevengetallenlijst)
print(len(onevengetallenlijst))
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199]
100

Een getal is dus deelbaar als er rest 0 uit komt. Getal%3==0 betekend dus dat een Getal deelbaar is door 3. We gaan in de volgende opdracht een lijst maken van getallen die ZOWEL deelbaar zijn door 3 als door 5. Om meerdere voorwaardes te checken kan je ‘and’ gebruiken. De tekst ‘als het getal deelbaar is door drie EN door 5’ wordt dat gedaan met if getal%3==0 and getal%5==0:

OPDRACHT

Maak een lijst van de eerste 20 positieve getallen die zowel deelbaar zijn door 3 als door 5. De eerste vijf getallen zijn dus 15, 30, 45, 60, 75 (0 tellen we NIET mee, dat is suf want is altijd ergens door deelbaar)
Print tenslotte de 10e getal in deze lijst, en tel daar dan de laatste getal in deze lijst bij op. Als je de opdracht goed hebt gedaan, is het antwoord 450

#noteer je code voor je opdracht hier, een klein begin is gemaakt
getal = 1
lijstje = []
while len(lijstje)<20:
  if(... and ...):
    ...

    
print(lijstje)
[15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300]

Meer over de while loop, verschil met for-loop en gevaren#

Je hebt een intro gekregen in het gebruik van de while loop. Eerder heb je de for loop gezien. Wanneer gebruik je welke? In het geval van lijsten:

  • de for loop gebruik je als je al een lijst hebt en je voor iedere item van die lijst iets wilt doen. Het aantal stappen is dan dus altijd eindig, namelijk de lengte van de lijst.

  • de while loop gebruik je als je NIET van te voren weet hoe lang je lijst zal gaan worden. Je wist bijvoorbeeld niet welke waarde de 20e item in de lijst van getallen die zowel deelbaar zijn door 3 als door 5 is.

Een groot gevaar van de while loop is de zogeheten ‘infinite loop’ of ‘deathloop’, het is mogelijk dat de loop NOOIT stopt. Je zal dit merken als de code onredelijk lang duurt, en je moet maar hopen dat je je programma weet te stoppen zonder je computer uit en aan te moeten zetten.

in onderstaande code gebeurd dit bijvoorbeeld, bedenk maar waarom dit mis gaat.

getal = 1
lijstje = []
lijstje.append(getal)
while len(lijstje)>0:
    lijstje.append(getal)
    getal = getal+1
print(len(lijstje))
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[29], line 4
      2 lijstje = []
      3 lijstje.append(getal)
----> 4 while len(lijstje)>0:
      5     lijstje.append(getal)
      6     getal = getal+1

KeyboardInterrupt: 

Een while loop kan je ook gebruiken als je graag eerder de code wilt stoppen dan je met een for loop zou willen. Een flauwe contextvraag: je gooit een bal van een toren van 120 meter hoog naar beneden. Elke 1 s gaat de bal 1.21 meter naar beneden. We willen weten op welk tijdstip de grond is bereikt.

Wiskundig kunnen we makkelijk berekenen welke tijdstip dit is: immers moet je enkel maar de formule 1.21t = 120 oplossen, dus t = 100/1.21 Maar we doen even alsof dit heel moeilijk is. En ja, het getal 1.21 is expres zo gekozen, dat zie je later…

Als je dit zou willen programmeren wil je na elke tijdstap de nieuwe hoogte bepalen, en dan checken of de hoogte nog boven nul is, anders is de grond bereikt. Je wilt ook de tijdstappen bijhouden. Een manier om dit te doen (nogmaals, er zijn altijd meerdere) is om twee lijsten bij te houden: de hoogte en tijd. Zolang de hoogte nog positief is, gaan we door met 1,21 m van de hoogte afhalen.

hoogte=120
tijd = 0
hoogtelijst = [120]    # we slaan alvast de eerste hoogte op, 120 m
tijdlijst = [0]        # we slaan ook alvast de eerste tijd op

while hoogtelijst[-1]>=0:
    hoogte = hoogte - 1.21
    tijd = tijd +1
    hoogtelijst.append(hoogte)
    tijdlijst.append(tijd)

print(tijdlijst[-1]) #hiermee printen we de laatste berekende tijd
print(hoogtelijst[-1]) #hiermee printen we de laatste bereknde hoogte
100
-0.9999999999997513

Een probleem dat we met de vorige code hebben is dat de laatste berekende waarde van de hoogte negatief is. Ergens tussen de laatste twee waarden zit dus de tijdstip waar de hoogte gelijk is aan 0. Bij het vak natuurkunde ga je hier verder mee aan de slag, door een kleinere tijdstap te gebruiken (dt = 0.0001 bijvoorbeeld). Dat slaan we voor nu even over, dat leer je bij natuurkunde wel

Meer wiskunde problemen oplossen met lijsten en modulo rekenen, en introductie FUNCTIES definieren.#

In dit hoofdstuk heb je kennis gemaakt met %-teken: 15%4 geeft de rest bij 15 gedeeld door 4. Bedenk zelf dat de uitkomst dan 3 is. We gebruiken modulo rekenen vooral bij vraagstukken waar je deelbaarheid moet testen.

In deze paragraaf gaan we een priemgetallenlijst generen en daar ga je in opdrachten weer mee verder werken.

Een priemgetal is een geheel getal groter dan 1, dat alleen door zichzelf deelbaar is. De eerste paar priemgetallen zijn dus 2, 3, 5, 7, 11 etc. 9 is dus geen priemgetal, want is deelbaar door 3.

We gaan een programma schrijven dat van een gegeven waarde, moet dat Getal, gaat controleren of deze priem is. Dit programma willen we later opnieuw aanroepen, dus we gaan een zogeheten functie definieren. dat gaat met def is_prime(getal).

Een manier om dat te doen is het Getal delen door alle getallen kleiner dat deze getal, noemen we nu Delers. Dit kan effecienter: we hoeven alleen de Delers te controleren kleiner dan de wortel van Getal. (als je wilt controleren of 100 een priem is, hoef je geen grotere getallen dan wortel(100) = 10 te checken)
Als er een deler is waarvoor geldt Getal%deler == 0, dan betekend dat het Getal goed gedeeld kan worden door Deler. Dus is Getal geen priem.

We willen dus onze met onze functie is_priem twee waarden terugkrijgen: WAAR (True) als het getal priem is en ONWAAR( False) als het geen priem is. Zie programma hieronder. je ziet twee keer return staan. Zodra er een deler is, wordt er return False gedaan, de for loop wordt dan ook gelijk gestopt. als er nooit een False is geweest, heeft het getal blijkbaar geen delers, dus sturen we True terug.

Nu we een functie hebben gemaakt dat controleert of een gegeven getal priem is, kunnen we een lijst van priemgetallen maken. De functie hieronder geeft alle priemgetallen kleiner dan 100. Probeer te begrijpen wat er gebeurd.

def is_priem(getal):
    delers = list(range(2,int(getal**0.5+1)))  #we hoeven niet verder te controleren tot de wortel van getal, echter moet in list een geheel getal staan, dus maken met int er een integer van.
    for deler in delers:
        if getal%deler == 0:
            return False #het getal is deelbaar door deler, dus is het getal geen priem
    return True #omdat er nooit een False is geweest, moet het getal dus wel priem zijn

is_prime(100)

priemlijst=[]
for getal in range(2,100):
    if is_priem(getal):
        priemlijst.append(getal)

print(priemlijst)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

EINDOPDRACHTEN#

Opdracht 1:
Maak een lijst van de eerste 100 priemtweelingen. Een priemtweeling is een paar priemgetallen die maar 2 verschillen, voorbeeld (3,5) en (5,7), …

#noteer hier de code, neem def is_prime over van de vorige paragraaf

Opdracht 2:
Geef de langste collatzrij onder 100. Een Collatzrij is een reeks getallen dat aan de volgende voorwaarden voldoet:
als het getal even is, halveer het
als het getal oneven is, vermenigvuldig met 3 en tel er 1 op. Voorbeeld van zo’n rij: [10, 5, 16, 8, 4, 2, 1] Het is een open probleem of een collatzrij altijd eindigt. Het einde van de collatzrij is altijd 1: 1x3+1 = 4, dan kom weer 2 en 1 uit. De lengte van collatzrijen verschillen, en er is eentje die heel lang is. Wat is de lengte van die rij, en print die rij ook uit.

Opdracht 3:
Schrijf een functie om te checken of drie getallen een zogeheten Pyathagorastriple is. Een Pythagorastriple (a,b,c) heeft de eigenschap dat a^2 + b^2 = c^2 voor a, b, c gehele positieve getallen.

Gebruik deze functie vervolgens om alle pythagorastriplets te vinden met a, b, c < 100. Sla dit op in een lijst. TIP: gebruik 3 for loops, en het inzicht dat a < b < c.

def pythtriple(a,b,c):
    ....
    
pythtriplelijst = []
...
...


print(pythtriplelijst)