Werken met sets
Inleiding
In voorgaande hoofdstukken leerde je over de lists en de tuples. In dit hoofdstuk leer je over de set
. Ook de set
is een collectie, maar heeft een heel andere functie dan de list
en de tuple
.
Het belangrijkste kenmerk van een set
is dat het enkel unieke elementen bevat. Verder gebruik je sets
met name om twee groepen elementen met elkaar te vergelijken (welk element is onderdeel van beide groepen, bijvoorbeeld).
Leerdoelen
Aan het einde van dit hoofdstuk:
-
Begrijp je wat een set is
-
Begrijp je in welke situatie je sets toe kunt passen
-
Begrijp je hoe je met elementen in een set kunt werken
Sets: een inleiding
In veel opzichten lijkt ook een set
op een list
. Het is een type collectie dat verschillende elementen kan bevatten, waar je langs kunt itereren en elementen aan kunt toevoegen of uit kunt halen.
Er zijn echter ook grote verschillen. In deze paragraaf leer je over de unieke eigenschappen van een set
en wanneer je een set
kunt gebruiken.
Kenmerken van sets
Een set
maak je op verschillende manieren:
lege_set = set()
set_met_items = {"a", "b", "c", }
mijn_list = [1, 2, 3, ]
mijn_set = set(mijn_list)
Een lege set
maak je altijd met de set()
-constructor. Omdat je een set
met elementen aanmaakt met accolades, verwacht je misschien dat je een lege set
ook met accolades aan kunt maken ({}
), maar dat is al gereserveerd om een lege dict
aan te maken!
Een set
bestaat altijd uit één of meer elementen tussen accolades, gescheiden door een komma.
De belangrijkste kenmerken van een set
zijn:
-
Een
set
is een type collectie. -
Een
set
zelf is muteerbaar, maar de elementen in eenset
mogen dat niet zijn. -
Elementen in een
set
mogen van verschillende typen zijn (als ze maar niet muteerbaar zijn). -
Elementen in een
set
zijn altijd uniek. -
De volgorde van elementen in een
set
staat niet vast.
Hashable
Net als de bij de sleutels van een Op Wikipedia lees je wat een hash is: nl.wikipedia.org/wiki/Hashfunctie |
Omdat een set
een collectie is, kun je er langs itereren. Verder zijn andere acties van collecties ook mogelijk:
-
Controleren of het element
i
in deset
aanwezig is meti in mijn_set
. -
Het aantal elementen ophalen met
len(mijn_set)
. -
Het kleinste en grootste element ophalen met
min(mijn_set)
enmax(mijn_set)
.
Indexering werkt niet, door de ongeordende structuur (de volgorde van elementen staat niet vast).
Geordend en ongeordend
Hoe zit dat met geordende en ongeordende datatypen? Een Stel je maakt een Als de elementen nu in een Kortom: de volgorde van aanmaken zegt niets over de volgorde van opslaan. Vandaar dat indexering niet werkt. En zoals je verderop ziet, heeft ook sorteren en omkeren door dit gegeven geen zin. |
Daarnaast zijn er nog een aantal acties die speciaal aan sets
zijn voorbehouden, hierover lees je in de volgende paragraaf.
Wanneer gebruik je sets
Een set
gebruik je vrijwel altijd om twee redenen:
-
Je wilt enkel met unieke waarden werken.
-
Je wilt verschillende groepen elementen met elkaar vergelijken.
Om een voorbeeld bij dit laatste te geven, stel dat je twee sets
met personen hebt, en je wilt weten welke persoon in beide sets
aanwezig is:
set_a = {"Marie", "John", "Erwin", }
set_b = {"Ali", "John", }
in_beide = set_a.intersection(set_b)
print(in_beide) # {"John"}
In de volgende paragraaf leer je meer van dergelijke berekeningen te maken.
Werken met elementen in een set
Een set
wijkt in meer opzichten af van een list
dan een tuple
doet. In deze paragraaf leer je hoe te werken met elementen in een set
, waarbij weer de nadruk ligt op handelingen die anders werken dan bij een list
.
Elementen uit een set ophalen
De set
is niet erg geschikt om met individuele elementen te werken. Een element uit een set
verkrijgen is dan ook niet eenvoudig. Indexering werkt bijvoorbeeld niet, door de ongeordende structuur. Je kunt .pop()
gebruiken om een willekeurig element uit de set te verkrijgen (en te verwijderen).
Wil je met één element uit een set
werken, dan kun je het beste langs alle elementen itereren, tot je het gewenste element bereikt hebt.
Sorteren en omkeren
Net als bij tuples
heeft een set
ook geen .sort()
en .reverse()
methodes. In dit geval niet omdat een set
niet aanpasbaar is (want dat is het wel), maar omdat een set
ongeordend is (zie kader eerder). Je kunt een set
wel sorteren (met sorted
), maar het zal de volgorde niet behouden. Wil je dit toch, dan dien je er (bijvoorbeeld) een list
of een tuple
van te maken.
Elementen aan een set toevoegen
Om een enkel element aan een set
toe te voegen gebruik je de .add()
methode. Om meerdere elementen uit een iterable toe te voegen, gebruik je .update()
(net als bij een list
).
mijn_set = {1, 2, 3, }
mijn_set.add(4)
print(mijn_set)
# {1, 2, 3, 4}
mijn_list = [5, 6, 7, ]
mijn_set.update(mijn_list)
print(mijn_set)
# {1, 2, 3, 4, 5, 6, 7}
Let op dat in beide gevallen geen foutmelding wordt gegeven als je een element toevoegt dat al in de set
aanwezig is.
Elementen uit een set verwijderen
Om een element uit een set
te verwijderen, gebruik je .remove()
of .discard()
. In beide gevallen geef je de waarde van het element op dat je wilt verwijderen. Het verschil tussen beiden is dat als het betreffende element niet bestaat, .remove()
een foutmelding geeft en .discard()
niet.
mijn_set = {1, 2, 3, 4, }
mijn_set.remove(1)
print(mijn_set)
# {2, 3, 4}
mijn_set.remove(5) # Fout
mijn_set.discard(5) # Geen fout
mijn_set.discard(2)
print(mijn_set)
# {3, 4}
Welke methode je gebruikt hangt af van de context. In veel gevallen wil je weten dat je een element probeert te verwijderen die er niet is en wil je dat afhandelen (hoe je dat doet, leer je in het hoofdstuk Werken met uitzonderingen). In die gevallen gebruik je .remove()
. Het kan echter zijn dat het geen probleem is dat je programma zonder melding doorloopt als je een element wilt verwijderen dat niet bestaat. In dat geval kun je .discard()
gebruiken.
Tot slot kun je - net als bij een list
of dict
- de methode .pop()
gebruiken. De werking is wel anders.
-
Bij een
list
verwijdert.pop()
het laatste element. Je kunt het ook een index meegeven om het element op die index te verwijderen. -
Bij een
dict
dien je altijd een sleutel mee te geven aan.pop()
. De waarde behorende bij die sleutel zal verwijderd worden. -
Bij een
set
kun je geen waarde aan.pop()
meegeven. Het verwijdert een willekeurig element uit deset
.
In alle gevallen wordt het verwijderde element ook teruggegeven.
Set vergelijkingen
Eén van de interessantere mogelijkheden van sets
is het vergelijken van de elementen in verschillende sets
. Uitgaande van set_1
en set_2
, kun je snel nagaan:
-
Welke elementen in
set_1
OF inset_2
(of beide) aanwezig zijn met.union
. -
Welke elementen in
set_1
EN inset_2
aanwezig zijn met.intersection
. -
Welke elementen in
set_1
maar NIET inset_2
aanwezig zijn met.difference
. -
Welke elementen in
set_1
OF inset_2
, maar NIET in beide aanwezig zijn met.symmetric_difference
.
Om de set-vergelijkingen te illustreren maak je de volgende drie sets
aan:
weekdagen = {
"maandag",
"dinsdag",
"woensdag",
"donderdag",
"vrijdag",
"zaterdag",
"zondag"
}
lesdagen = {"maandag", "woensdag", "vrijdag"}
sportdagen = {"woensdag", "zondag"}
Allereerst zie je een set
met alle dagen van de week. De andere twee sets
zijn de dagen waarop je les hebt en waarop je sport.
Venn
Als je met In elke cirkel noteer je de elementen, de elementen die in beide Er zijn ook online tools die dit automatisch voor je doen, zie bijvoorbeeld: goodcalculators.com/venn-diagram-maker/ |
Union
Om nu na te gaan op welke dagen je iets hebt (sport, les, of beide) gebruik je .union
:
# Union: dagen met les, sport of beide
bezette_dagen = lesdagen.union(sportdagen)
print(bezette_dagen)
# {'maandag', 'vrijdag', 'zondag', 'woensdag'}
Intersection
Om na te gaan wanneer je zowel sport als les hebt, gebruik je .intersection
:
# Intersection: dagen met les én sport
drukke_dagen = lesdagen.intersection(sportdagen)
print(drukke_dagen)
# {'woensdag'}
Difference
Om na te gaan op welke dagen je vrij hebt (dus geen sport en geen les), ga je het verschil na tussen de weekdagen
en de bezette_dagen
:
# Difference: dagen in weekdagen, maar niet in bezette dagen
vrije_dagen = weekdagen.difference(bezette_dagen)
print(vrije_dagen)
# {'dinsdag', 'donderdag', 'zaterdag'}
Je bekijkt zo de weekdagen die niet in bezette_dagen
aanwezig zijn.
Als je het omdraait, dan bekijk je de bezette dagen die niet in weekdagen
aanwezig zijn. Dat levert een lege set
op, omdat alle dagen in bezette_dagen
ook in weekdagen
aanwezig is.
Symmetric Difference
Tot slot kun je nog nagaan op welke dag je maar één iets hebt (of les, of sport, maar niet beide):
# Symmetric Difference: dagen in lesdagen of sportdagen, maar niet in beide
een_ding = lesdagen.symmetric_difference(sportdagen)
print(een_ding)
# {'maandag', 'zondag', 'vrijdag'}
Subset, superset, disjoint
Daarnaast zijn er methodes om na te gaan of set_1
:
-
Een subset is van
set_2
(alle elementen vanset_1
zijn ook aanwezig inset_2
). -
Een superset is van
set_2
(alle elementen vanset_2
zijn ook aanwezig inset_1
). -
Er geen enkele overlap is (geen enkel element van
set_1
bevindt zich inset_2
).
Neem de volgende, iets aangepaste sets
:
weekdagen = {
"maandag",
"dinsdag",
"woensdag",
"donderdag",
"vrijdag",
}
weekend = {"zaterdag", "zondag",}
lesdagen = {"maandag", "woensdag", "vrijdag"}
sportdagen = {"woensdag", "zondag"}
Je controleert eenvoudig of alle lesdagen onderdeel zijn van weekdagen met .issubset
. Hetzelfde doe je voor de sportdagen:
lessen_in_week = lesdagen.issubset(weekdagen)
print(lessen_in_week) # True
sport_in_week = sportdagen.issubset(weekdagen)
print(sport_in_week) # False
Andersom kun je controleren of alle dagen van de week de lesdagen omvatten:
week_lessen = weekdagen.issuperset(lesdagen)
print(week_lessen) # True
En tot slot kun je nagaan of twee sets
totaal geen overlap hebben, zoals doordeweeks en het weekend:
geen_overlap = weekdagen.isdisjoint(weekend)
print(geen_overlap) # True
Operatoren
In plaats van bijvoorbeeld
Zie docs.python.org/3.11/library/stdtypes.html#set voor alle operatoren en hun gebruik. |