1.3 Herhaling

Dezelfde bewerking meermaals, zonder ze meermaals op te schrijven

OpmerkingLeerdoelen

Na deze les kan je:

  • een for-lus schrijven die een vast aantal keren herhaalt
  • range gebruiken om te bepalen hoe vaak en met welke waarden
  • de waarden in een lus volgen met een trace table
  • herkennen welke regels binnen de lus horen en welke erbuiten

De vorige les eindigde bij een programma dat een totaal kan bijhouden, zij het met één regel per artikel. Een mandje met twintig artikelen vergt dan twintig regels, en een teller die tot honderd loopt honderd. In deze les vervang je zo’n reeks door twee regels.

1 Hetzelfde, tien keer

Neem de tafel van zeven. Met wat je al weet uit de vorige lessen, ziet ze er zo uit.

Tien regels, en ze verschillen op precies één plaats: het getal dat van \(1\) tot \(10\) loopt. Al de rest staat er tien keer identiek bij. Voor zo’n reeks bijna identieke instructies heeft Python een aparte vorm.

2 De lus

Een lus voert een blok regels meermaals uit. De vorm ligt vast.

De naam i is de lusvariabele. Ze krijgt bij elke iteratie een volgende waarde uit range(1, 11), en dat zijn de getallen van \(1\) tot en met \(10\). Het geïndenteerde blok wordt telkens opnieuw uitgevoerd, met die ene waarde ingevuld.

Van range moet je twee vormen kennen.

vorm levert
range(5) \(0, 1, 2, 3, 4\)
range(1, 11) \(1, 2, \ldots, 10\)

De bovengrens hoort er in beide gevallen niet bij. Dat oogt vreemd en het heeft een voordeel: range(5) telt precies vijf waarden af, en range(a, b) telt er precies \(b - a\).

Tien regels zijn twee regels geworden, en de tafel van acht kost geen enkele regel extra.

3 Wat er bij elke iteratie verandert

De accumulator uit de vorige les hoort thuis in een lus. Hieronder telt een programma de getallen van \(1\) tot en met \(4\) op.

De trace table krijgt er een rij per iteratie bij, en een kolom voor de lusvariabele.

iteratie i totaal
voor de lus 0
1 1 1
2 2 3
3 3 6
4 4 10
na de lus 4 10

Twee dingen vallen op. De lusvariabele krijgt haar waarde van range en jij kent ze nooit zelf toe. De accumulator daarentegen draagt zijn waarde van de ene iteratie naar de volgende, en daarom moet hij vóór de lus een beginwaarde krijgen.

De laatste rij zegt dat i blijft bestaan nadat de lus is afgelopen, met de waarde die ze in de laatste iteratie kreeg. Bouw daar verder niets op: een lusvariabele hoort bij haar lus, en je gebruikt ze enkel binnen het geïndenteerde blok.

4 Binnen of buiten de lus

De indentatie uit les 1.1 bepaalt hier wat er herhaald wordt. Alles wat geïndenteerd staat, gebeurt bij elke iteratie. Alles wat daarna tegen de kantlijn staat, gebeurt één keer, wanneer de lus afgelopen is.

In de cel hierboven staat print(totaal) buiten de lus, dus verschijnt enkel het eindresultaat 10. Zet je die regel geïndenteerd, dan verschijnen er vier regels, namelijk de tussenstanden 1, 3, 6 en 10. Beide zijn zinvol, en welke je nodig hebt, hangt af van wat je wil zien.

WaarschuwingOpgelet

Zet de beginwaarde van een accumulator vóór de lus, niet erin. Staat totaal = 0 geïndenteerd, dan begint het totaal bij elke iteratie opnieuw bij nul en blijft er op het einde enkel de laatste waarde over.

5 Een lus in een functie

Een lus in een functie levert iets op dat je overal kan hergebruiken.

De n + 1 zorgt ervoor dat n zelf meetelt, aangezien de bovengrens er niet bij hoort. Merk op dat de drie bouwstenen van de vorige lessen hier samenkomen: een functie die een waarde teruggeeft, een accumulator die aangroeit, en een lus die het werk herhaalt.

De som van de eerste \(n\) getallen kan ook zonder lus:

\[ 1 + 2 + \ldots + n = \frac{n(n+1)}{2} . \]

Voor de uitkomst maakt dat niets uit, voor het werk wel. som_tot(100) doet honderd iteraties, de formule doet één berekening. Bij honderd getallen merk je daar niets van, bij een miljard wel. Een herhaling vervangen door één formule is een van de sterkste ingrepen die je op een programma kan doen.

6 Conclusie

Een lus voert hetzelfde blok meermaals uit, met bij elke iteratie een andere waarde in de lusvariabele. Wat geïndenteerd staat, hoort bij de lus, en wat erna komt gebeurt één keer. Een accumulator krijgt zijn beginwaarde ervoor en draagt zijn waarde doorheen alle iteraties.

Wat een for-lus niet kan, is stoppen zodra iets waar is. Ze telt een vast aantal iteraties af en meer niet. Om een programma te laten kiezen heb je voorwaarden nodig, en die komen later aan bod.

In de volgende les loopt een lus niet over getallen maar over de letters van een tekst, en dan wordt ze pas echt bruikbaar.

7 Begrippen

  • lus (loop): een blok regels dat meermaals na elkaar uitgevoerd wordt.
  • lusvariabele (loop variable): de naam die bij elke iteratie een volgende waarde krijgt.
  • iteratie (iteration): één keer het blok van de lus uitvoeren.
  • range: de reeks getallen die een for-lus afloopt, met de bovengrens er niet bij.

8 Oefeningen

  1. Beantwoord zonder de computer.

    1. Hoe vaak wordt de geïndenteerde regel uitgevoerd bij for i in range(4):, en welke waarden krijgt i?

    2. Maak een trace table voor de code hieronder en geef het eindresultaat.

    3. Wat verschijnt er als je in die code print(totaal) geïndenteerd zet, zodat hij binnen de lus valt?

    a. Vier keer, met i gelijk aan \(0\), \(1\), \(2\) en \(3\). De bovengrens \(4\) hoort er niet bij.

    b. 14.

    iteratie i totaal
    voor de lus 0
    1 1 1
    2 2 5
    3 3 14

    c. Drie regels, namelijk 1, 5 en 14. Je ziet dan de tussenstanden in plaats van enkel het eindresultaat.

  2. Vul de cel hieronder aan.

    Je hebt de getallen van \(1\) tot en met \(10\) nodig, en de bovengrens hoort er niet bij.

  3. De functie hieronder moet het product van de getallen van \(1\) tot en met n teruggeven. Voor n gelijk aan \(5\) is dat \(1 \cdot 2 \cdot 3 \cdot 4 \cdot 5\), dus \(120\).

    Bij een som gebruik je +=. Voor een product bestaat *=, dat op dezelfde manier werkt.

    De beginwaarde is hier \(1\) en niet \(0\), aangezien alles maal nul weer nul is.

  4. Schrijf gemiddelde_tot(n), die het gemiddelde teruggeeft van de getallen van \(1\) tot en met n. Voor n gelijk aan \(10\) is dat 5.5.

    som_tot hierboven telt die getallen al op en je kan haar hier aanroepen. Een gemiddelde is die som gedeeld door het aantal getallen, en dat delen gebeurt één keer.

    Er verschijnt 5.5. De deling staat na de lus en niet erin, aangezien ze binnen de lus op een onvolledig totaal zou werken. Dat een deling met / een kommagetal oplevert, ken je uit les 1.2.

  5. Een spaarrekening van \(1000\) euro brengt elk jaar \(5\%\) op, telkens op het bedrag dat er op dat ogenblik staat. Bereken hoeveel er na tien jaar staat, en toon met int() de volle euro’s.

    Vijf procent van kapitaal is kapitaal * 0.05, en dat komt er elk jaar bij. De lus moet tien keer lopen, dus volstaat range(10).

    Er verschijnt 1628. Het kommagetal zelf heeft een lange staart na de komma, en int() houdt daarvan de volle euro’s over. Merk op dat de lusvariabele in het blok niet voorkomt: range(10) dient hier enkel om tien keer af te tellen.

  1. In de rij van Fibonacci is elk getal de som van de twee die eraan voorafgaan, en ze begint met \(1\) en \(1\). Laat de eerste tien getallen van de rij verschijnen. Je hebt twee namen nodig die bij elke iteratie opschuiven.

    Zodra je huidige een nieuwe waarde geeft, is de oude nergens meer te vinden. Bewaar ze eerst onder een derde naam, net zoals bij het verwisselen in les 1.2.

    Er verschijnen 1, 1, 2, 3, 5, 8, 13, 21, 34 en 55. De derde naam is nodig omdat de toekenning aan huidige de waarde overschrijft die vorige daarna nog nodig heeft.