Les 5
Lijsten, tuples en sets
De juiste collectie kiezen: volgorde, onveranderlijkheid of uniciteit.
🎯 Na deze les kun je
- het verschil tussen list, tuple en set uitleggen
- setbewerkingen gebruiken
- tuple-unpacking toepassen
Python heeft drie ingebouwde manieren om een reeks waarden te bewaren: lijsten, tuples en sets. Ze lijken op elkaar, maar de keuze maakt verschil. Kies je goed, dan is je code duidelijker, sneller en beschermd tegen een hele groep fouten. In deze les leer je wanneer je welke gebruikt, hoe je waarden handig uitpakt (unpacking), en hoe je met sets in één regel vergelijkt wat twee groepen gemeen hebben.
List versus tuple
boodschappen = ["melk", "brood", "kaas"] # list: vierkante haken
punt = (52.09, 5.12) # tuple: ronde haken
boodschappen.append("eieren")
print(boodschappen)
punt[0] = 51.0
['melk', 'brood', 'kaas', 'eieren']
TypeError: 'tuple' object does not support item assignment
Een list is veranderlijk (mutable): je kunt toevoegen, verwijderen en vervangen. Een tuple is onveranderlijk (immutable): eenmaal gemaakt blijft hij zo.
Wanneer kies je wat?
| list | tuple | |
|---|---|---|
| Typisch gebruik | een verzameling van gelijksoortige dingen, waarvan het aantal kan veranderen | een vaste groep waarden die samen één ding vormen |
| Voorbeeld | alle bestellingen van vandaag | een coördinaat (lat, lon), een RGB-kleur (255, 128, 0) |
| Veranderen | ja | nee |
| Als sleutel in een dict of element van een set | nee | ja (als de inhoud ook onveranderlijk is) |
Een tuple met één element vraagt om een komma: (5,). Zonder komma is (5) gewoon het getal 5 tussen haakjes.
Een belangrijke valkuil met lijsten: een toekenning maakt geen kopie, maar een tweede naam voor dezelfde lijst.
a = [1, 2, 3]
b = a
b.append(4)
print(a)
c = a.copy()
c.append(5)
print(a, c)
[1, 2, 3, 4]
[1, 2, 3, 4] [1, 2, 3, 4, 5]
Bij een tuple kan dit niet misgaan, omdat niemand hem kan veranderen. Dat is een van de redenen om voor een tuple te kiezen.
Unpacking
Een reeks kun je in één keer uitpakken in losse variabelen:
punt = (52.09, 5.12)
lat, lon = punt
print(lat)
a, b = 1, 2
a, b = b, a # wisselen zonder hulpvariabele
print(a, b)
eerste, *rest = [10, 20, 30, 40]
print(eerste, rest)
*begin, laatste = "abcd"
print(begin, laatste)
52.09
2 1
10 [20, 30, 40]
['a', 'b', 'c'] d
Met een * vang je "de rest" op in een lijst. Het aantal namen moet anders precies kloppen:
x, y = (1, 2, 3)
ValueError: too many values to unpack (expected 2)
Unpacking werkt ook in een for-lus, en dat zie je overal:
steden = [("Utrecht", 361_000), ("Zwolle", 132_000)]
for naam, inwoners in steden:
print(f"{naam}: {inwoners:,}")
for index, stad in enumerate(["Gouda", "Delft"]):
print(index, stad)
Utrecht: 361,000
Zwolle: 132,000
0 Gouda
1 Delft
enumerate en zip geven tuples terug, die je zo meteen uitpakt.
Sets
Een set is een verzameling zonder volgorde en zonder dubbele waarden:
bezoekers = ["sam", "noor", "sam", "ali", "noor"]
uniek = set(bezoekers)
print(len(bezoekers), len(uniek))
print("ali" in uniek)
5 3
True
De volgorde van een set is niet vast; print je hem, dan kan de volgorde anders zijn dan je verwacht. Wil je een gesorteerde lijst, gebruik dan sorted(uniek).
Opzoeken met in is bij een set heel snel, ook bij miljoenen elementen. Bij een lijst moet Python alle elementen langslopen. Moet je vaak controleren of iets erin zit, gebruik dan een set (meer hierover in les 34).
Verzamelingsbewerkingen
cursus_a = {"sam", "noor", "ali", "lisa"}
cursus_b = {"noor", "lisa", "tim"}
print(sorted(cursus_a & cursus_b)) # in beide (doorsnede)
print(sorted(cursus_a | cursus_b)) # in een van beide (vereniging)
print(sorted(cursus_a - cursus_b)) # alleen in a (verschil)
print(sorted(cursus_a ^ cursus_b)) # in precies één van beide
['lisa', 'noor']
['ali', 'lisa', 'noor', 'sam', 'tim']
['ali', 'sam']
['ali', 'sam', 'tim']
Een lege set maak je met set(). {} is een lege dictionary (les 6).
Elementen van een set moeten onveranderlijk zijn: getallen, strings en tuples mogen, lijsten niet (TypeError: unhashable type: 'list').
Uitgewerkt voorbeeld: wie is er nieuw?
Je hebt de ledenlijst van vorig jaar en van dit jaar, met dubbele invoer. Wie is er nieuw, wie is vertrokken? Voorspel de uitvoer.
vorig_jaar = ["Sam", "Noor", "Ali", "Noor", "Lisa"]
dit_jaar = ["Noor", "Lisa", "Tim", "Eva", "Tim"]
oud = set(vorig_jaar)
nieuw = set(dit_jaar)
print("Nieuw:", ", ".join(sorted(nieuw - oud)))
print("Vertrokken:", ", ".join(sorted(oud - nieuw)))
print("Gebleven:", len(oud & nieuw))
Nieuw: Eva, Tim
Vertrokken: Ali, Sam
Gebleven: 2
Met lijsten en lussen was dit een veel langer stuk code geweest.
Veelgemaakte fouten
b = aen denken dat je een kopie hebt. Gebruika.copy()oflist(a).(5)in plaats van(5,)voor een tuple met één element.{}gebruiken voor een lege set.- Rekenen op de volgorde van een set.
Oefenen
Oefening 1. Verwijder de dubbele waarden uit [3, 1, 3, 2, 1], maar behoud de volgorde waarin ze het eerst voorkwamen: [3, 1, 2].
Modelantwoord oefening 1
getallen = [3, 1, 3, 2, 1]
gezien = set()
uniek = []
for g in getallen:
if g not in gezien:
gezien.add(g)
uniek.append(g)
print(uniek)
print(list(dict.fromkeys(getallen)))
[3, 1, 2]
[3, 1, 2]
set(getallen) alleen verliest de volgorde. De tweede regel is een bekende truc: de sleutels van een dictionary blijven in invoegvolgorde (les 6).
Oefening 2. Pak record = ("Noor", "Jansen", 34, "Utrecht") uit, zodat naam de voornaam bevat en woonplaats de laatste waarde, en de rest wordt genegeerd.
Modelantwoord oefening 2
record = ("Noor", "Jansen", 34, "Utrecht")
naam, *_, woonplaats = record
print(naam, woonplaats)
Noor Utrecht
_ is de gebruikelijke naam voor een waarde die je niet gebruikt.
Oefening 3. Waarom kun je een tuple (52.09, 5.12) als sleutel in een dictionary gebruiken, maar een lijst [52.09, 5.12] niet?
Modelantwoord oefening 3
Sleutels (en set-elementen) moeten hashable zijn: hun waarde mag niet veranderen, anders kan Python ze niet terugvinden. Een tuple is onveranderlijk, een lijst niet. Probeer je het toch, dan krijg je TypeError: unhashable type: 'list'.
Lab: deelnemerslijsten vergelijken
- In
deelnemers.pystaan drie lijsten met e-mailadressen van deelnemers aan drie workshops, met dubbele invoer en verschillen in hoofdletters. - Schrijf
normaliseer(lijst)die een set met adressen in kleine letters en zonder spaties teruggeeft. - Schrijf
alle_drie(a, b, c),precies_een(a, b, c)ennieuwe_deelnemers(oud, nieuw)met verzamelingsbewerkingen. Geef gesorteerde lijsten terug. - Schrijf
afstanden(punten), dat een lijst(naam, (x, y))-tuples krijgt en met unpacking voor elk punt de afstand tot(0, 0)berekent. - Controleer met
beetje check python-les5.
Samenvatting
- list: veranderlijke reeks; tuple: onveranderlijke vaste groep; set: unieke waarden zonder volgorde.
b = amaakt geen kopie van een lijst;a.copy()wel.- Unpacking:
x, y = punt,a, b = b, a,eerste, *rest = lijst, ook infor-lussen. - Sets zijn snel voor
inen hebben&,|,-en^.
In les 6 gebruik je dictionaries, ook genest en met Counter en defaultdict.
Lab
Gemeenschappelijke vakken van twee klassen vinden
💻 Dit lab doe je op je eigen computer met Docker. Start de lab-container met (geeft de opdracht een eigen startcommando, gebruik dan dat):
$ docker run -it --rm registry.wizg.it/webhosting/beetje-labs:python-les5
Klaar? Controleer je werk met:
$ beetje check python-les5