`Set`-object

Dit artikel legt het Set-object uit.

We zullen het Set-object uitleggen met praktische voorbeelden.

YouTube Video

Set-object

Set is een ingebouwd object waarmee je verzamelingen van unieke, niet-gedupliceerde waarden kunt beheren. Het maakt het eenvoudiger om dubbele waarden te verwijderen en te controleren op bestaan dan met arrays, en maakt verzamelbewerkingen zoals unie en doorsnede makkelijker te implementeren.

Basis: Sets maken en gebruiken

Laten we eerst kijken hoe je een Set maakt, elementen toevoegt en verwijdert, controleert op bestaan en de grootte opvraagt.

Hieronder volgt een basisvoorbeeld waarin een nieuwe Set wordt gemaakt en de methoden add, has, delete en size worden getoond.

 1// Create a Set and demonstrate add, has, delete, and size
 2const s = new Set();
 3
 4s.add(1);
 5s.add(2);
 6s.add(2); // duplicate, ignored
 7
 8console.log(s.has(1)); // true
 9console.log(s.has(3)); // false
10
11s.delete(2);
12console.log(s.size); // 1
13
14console.log([...s]); // [1]
  • Zoals in deze code te zien is, verwijdert Set automatisch dubbele primitieve waarden en kun je het aantal elementen verkrijgen met size.

Iteratiemethoden

Set is iterabel, dus je kunt erover itereren met for...of of forEach. De volgorde is de invoegvolgorde.

Hier zijn typische manieren om for...of en forEach te gebruiken.

 1// Iterate a Set with for...of and forEach
 2const s = new Set(['a', 'b', 'c']);
 3
 4for (const v of s) {
 5  console.log('for...of:', v);
 6}
 7
 8s.forEach((value, sameValue, setRef) => {
 9  // Note: second arg is same as first for Set API to match Map signature
10  console.log('forEach:', value);
11});
  • De callback-signatuur voor forEach is value, value, set (voor compatibiliteit met Map), maar in de praktijk heb je meestal alleen het eerste value-argument nodig.

Conversie tussen arrays en sets (handig om duplicaten te verwijderen)

Hier laten we een eenvoudige techniek zien om duplicaten uit een array te verwijderen, en hoe je een Set weer omzet naar een array.

Hieronder een voorbeeld om duplicaten uit een array te verwijderen door deze via een Set te halen.

1// Deduplicate an array using Set
2const arr = [1, 2, 2, 3, 3, 3];
3const deduped = [...new Set(arr)];
4console.log(deduped); // [1, 2, 3]
5
6// Convert a Set to an array using Array.from
7const s = new Set([4, 5, 6]);
8const arrFromSet = Array.from(s);
9console.log(arrFromSet); // [4, 5, 6]
  • Dit patroon is kort en snel, en wordt daarom vaak gebruikt om duplicaten uit arrays te verwijderen. Het is vooral effectief voor primitieve waarden.

Objecten en referentieafhandeling

Objecten in een Set worden vergeleken op basis van referentie, dus verschillende instanties met dezelfde inhoud worden als aparte elementen beschouwd.

De volgende code demonstreert wat er gebeurt als je objecten toevoegt aan een Set.

 1// Objects are compared by reference in a Set
 2const obj1 = { x: 1 };
 3const obj2 = { x: 1 };
 4
 5const s = new Set();
 6s.add(obj1);
 7s.add(obj2);
 8
 9console.log(s.size); // 2 (different references)
10console.log(s.has(obj1)); // true
11console.log(s.has({ x: 1 })); // false (different object)
  • Dubbelherkenning voor objecten is gebaseerd op referentie-identiteit, dus als je wilt dedupliceren op basis van alleen de inhoud van objecten, moet je ze serialiseren of op een andere manier verwerken.

Speciale waarden: omgaan met NaN en -0/+0

Set gebruikt de Same-value-zero vergelijkingsregel om waarde-gelijkheid te bepalen. Deze vergelijkingsmethode heeft de volgende eigenschappen met betrekking tot getallen:.

  • NaN wordt beschouwd als gelijk aan NaN.
  • Positieve +0 en negatieve -0 worden niet onderscheiden en worden als dezelfde waarde behandeld.

Daarom treedt het volgende gedrag op wanneer je deze waarden toevoegt aan een Set:.

 1// NaN and zero behavior in Set
 2const s = new Set();
 3
 4s.add(NaN);
 5s.add(NaN);
 6console.log(s.size); // 1 (NaN considered the same)
 7
 8s.add(+0);
 9s.add(-0);
10console.log(s.size); // still 2 (NaN + 0)
11console.log([...s]); // [NaN, 0] (order may vary but only one zero)
  • Bij normale vergelijking (NaN === NaN) geeft dit false, maar binnen een Set worden alle NaN-waarden als 'dezelfde waarde' beschouwd.
  • +0 en -0 zijn wiskundig te onderscheiden, maar in een Set worden ze gewoon als 0 behandeld.
  • Als resultaat blijft er slechts één NaN en één 0 over in de Set.
  • De vergelijkingsregel van Set lijkt op Object.is, maar is niet precies hetzelfde. Object.is(+0, -0) geeft false terug, maar in een Set worden ze als identiek beschouwd. Let goed op dit verschil.

Veelgebruikte functionaliteit: setoperaties (unie, doorsnede, verschil)

Setoperaties kunnen duidelijker worden geschreven met behulp van Set. Hieronder vind je veelgebruikte implementatievoorbeelden.

Hier zijn voorbeelden van functies voor union, intersection, en difference.

 1// Set operations: union, intersection, difference
 2function union(a, b) {
 3  return new Set([...a, ...b]);
 4}
 5
 6function intersection(a, b) {
 7  return new Set([...a].filter(x => b.has(x)));
 8}
 9
10function difference(a, b) {
11  return new Set([...a].filter(x => !b.has(x)));
12}
13
14// Demo
15const A = new Set([1, 2, 3]);
16const B = new Set([3, 4, 5]);
17
18console.log('union', [...union(A, B)]); // [1,2,3,4,5]
19console.log('intersection', [...intersection(A, B)]); // [3]
20console.log('difference A\\B', [...difference(A, B)]); // [1,2]
  • Setoperaties kun je eenvoudig schrijven door filters te gebruiken in combinatie met Set en arrays. Bij grote datasets zorgt de O(1)-prestatie van has ervoor dat bewerkingen sneller verlopen.

Praktisch voorbeeld: verschillen tussen arrays vinden (toegevoegde/verwijderde items detecteren)

Het volgende voorbeeld laat zien hoe je een Set gebruikt om het verschil tussen twee arrays te bepalen (een oude lijst en een nieuwe lijst). Hiermee kun je bepalen welke elementen zijn toegevoegd en welke zijn verwijderd.

 1// Find added and removed items between two arrays
 2function diffArrays(oldArr, newArr) {
 3  const oldSet = new Set(oldArr);
 4  const newSet = new Set(newArr);
 5
 6  const added = [...newSet].filter(x => !oldSet.has(x));
 7  const removed = [...oldSet].filter(x => !newSet.has(x));
 8
 9  return { added, removed };
10}
11
12const oldList = [1, 2, 3];
13const newList = [2, 3, 4, 5];
14
15console.log(diffArrays(oldList, newList));
16// { added: [4,5], removed: [1] }
  • Deze methode is erg handig om verschillen te detecteren in ID-lijsten, taglijsten en vergelijkbare situaties. Het is het eenvoudigst te gebruiken met primitieve waarden.

Verschillen tussen WeakSet en Set (geheugenbeheer)

WeakSet lijkt op Set, maar gebruikt zwakke referenties, waardoor de items kunnen worden opgeruimd door de garbage collector. Het volgende laat het basisgebruik van WeakSet zien.

1// WeakSet basics (objects only, not iterable)
2const ws = new WeakSet();
3let obj = { id: 1 };
4ws.add(obj);
5
6console.log(ws.has(obj)); // true
7
8obj = null; // Now the object is eligible for GC; WeakSet won't prevent collection

WeakSet kan alleen objecten bevatten en kan niet worden geïtereerd. Hieronder vind je voorbeelden van de beperkingen van WeakSet—het bevat alleen objecten en is niet itereerbaar.

 1// WeakSet basics (objects only, not iterable)
 2const ws = new WeakSet();
 3
 4// --- Only objects can be added ---
 5try {
 6	ws.add(1); // number
 7} catch (e) {
 8	console.log("Error: WeakSet can only store objects. Adding a number is not allowed.");
 9}
10
11try {
12	ws.add("text"); // string
13} catch (e) {
14	console.log("Error: WeakSet can only store objects. Adding a string is not allowed.");
15}
16
17// --- WeakSet is not iterable ---
18try {
19	for (const value of ws) {
20		console.log(value);
21	}
22} catch (e) {
23	console.log("Error: WeakSet is not iterable. You cannot use for...of to loop over its elements.");
24}
25
26// --- Cannot convert to array ---
27try {
28	console.log([...ws]);
29} catch (e) {
30	console.log("Error: WeakSet cannot be converted to an array because it does not support iteration.");
31}
32
33// The object becomes eligible for garbage collection
34let obj = { id: 1 };
35ws.add(obj);
36obj = null;
  • WeakSet is handig om tijdelijk het bestaan van objecten bij te houden, maar je kunt zijn elementen niet opsommen of de grootte opvragen.

Prestatie en het kiezen van het juiste gebruiksmoment

Bij het beslissen of je een Set wilt gebruiken, is het belangrijk om de prestatiekenmerken en de aard van je gegevens te begrijpen.

  • has, add en delete werken doorgaans met een bijna O(1)-prestatie gemiddeld genomen. Daarom is Set vaak voordeliger dan arrays in scenario's waarbij je vaak controleert op bestaan of duplicaten verwijdert.
  • Wees voorzichtig als je objecten wilt dedupliceren op basis van hun inhoud (waarden). Omdat Set vergelijkt op basis van referentie, is het in de praktijk handig om ID's of andere sleutels te gebruiken, of objecten te serialiseren tot primitieve waarden voordat je Sets gebruikt wanneer vergelijking op basis van waarde nodig is.
  • Set is bijzonder nuttig om de code leesbaarder te maken voor kleine tot middelgrote verzamelingen. Aan de andere kant, als je werkt met een zeer groot aantal elementen of vaak converteert tussen arrays en Sets, wordt het aanbevolen om daadwerkelijk te benchmarken en te testen.

Veelvoorkomende valkuilen

Set is handig, maar als je zijn specificaties niet kent, kun je verrast worden door onverwachte gedragingen. Hier zijn een aantal typische aandachtspunten:.

  • Objecten worden vergeleken op basis van referentie; zelfs als hun inhoud gelijk is, worden verschillende objecten niet als duplicaten beschouwd.
  • Set behoudt de invoegvolgorde, maar je kunt geen elementen op index benaderen zoals bij arrays. Als je toegang op basis van index wilt, zet de Set dan eerst om in een array.
  • WeakSet kan niet worden opgesomd en kan alleen objecten opslaan. Houd er rekening mee dat het toepassingsgebied beperkt is.
  • NaN wordt behandeld als dezelfde waarde, en +0 en -0 worden niet onderscheiden. Dit komt door de Same-value-zero vergelijkingsregel.

Samenvatting

Set is een handige datastructuur waarmee je verzamelingen van unieke waarden op een intuïtieve manier kunt beheren. Je kunt het gebruiken om duplicaten uit arrays te verwijderen, snelle bestaanchecks uit te voeren, of setoperaties zoals unie en doorsnede te implementeren met simpele en leesbare code.

Daarentegen, omdat objecten op referentie worden vergeleken, zijn extra maatregelen nodig als je gelijkheid op inhoud wilt controleren.

Door deze eigenschappen te begrijpen en ze juist toe te passen, wordt Set een krachtige keuze om de leesbaarheid en het onderhoud van je code te verbeteren.

Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.

YouTube Video