Objektet `Set`

Denna artikel förklarar objektet Set.

Vi förklarar objektet Set med praktiska exempel.

YouTube Video

Objektet Set

Set är ett inbyggt objekt som används för att hantera samlingar av unika, icke-duplicerade värden. Det låter dig skriva borttagning av dubbletter och existenskontroller enklare än med arrayer, och gör mängdoperationer som union och snitt lättare att implementera.

Grunder: Skapa och använda Set

Först tittar vi på hur man skapar ett Set, lägger till och tar bort element, kontrollerar om ett värde finns och hämtar dess storlek.

Nedan är ett grundläggande exempel som skapar ett nytt Set och demonstrerar add, has, delete och size.

 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]
  • Som visas i denna kod tar Set automatiskt bort dubbletter av primitiva värden, och du kan få antalet element med hjälp av size.

Itereringsmetoder

Set är itererbar, så du kan loopa över den med hjälp av for...of eller forEach. Ordningen är insättningsordningen.

Här är typiska sätt att använda for...of och forEach.

 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});
  • Signaturen för callback-funktionen i forEach är value, value, set (för kompatibilitet med Map), men i praktiken använder du oftast bara det första argumentet value.

Konvertering mellan arrayer och Set (användbart för att ta bort dubbletter)

Här visar vi en enkel teknik för att ta bort dubbletter från en array och hur du konverterar ett Set tillbaka till en array.

Nedan är ett exempel på att ta bort dubbletter från en array genom att skicka den genom ett Set.

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]
  • Detta mönster är kort och snabbt, så det används ofta för att ta bort dubbletter i arrayer. Det är särskilt effektivt för primitiva värden.

Objekt och referenshantering

Objekt i ett Set jämförs med referenser, så olika instanser med samma innehåll behandlas som separata element.

Följande kod visar vad som händer när du lägger till objekt i ett 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)
  • Upptäckt av dubbletter för objekt baseras på referensidentitet, så om du vill ta bort dubbletter baserat på objektinnehåll måste du serialisera eller bearbeta dem på annat sätt.

Speciella värden: Hantering av NaN och -0/+0

Set använder jämförelseregeln Same-value-zero för att avgöra värdeekvivalens. Denna jämförelsemetod har följande egenskaper för siffror:.

  • NaN anses vara lika med NaN.
  • Positivt +0 och negativt -0 särskiljs inte utan behandlas som samma värde.

Därför, när du lägger till dessa värden i ett Set, uppstår följande beteende:.

 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)
  • Vid normal jämförelse (NaN === NaN) returneras false, men i ett Set betraktas alla NaN-värden som 'samma värde'.
  • +0 och -0 kan särskiljas matematiskt, men i ett Set behandlas de helt enkelt som 0.
  • Därför finns bara en NaN och en 0 kvar i Set.
  • Jämförelseregeln för Set liknar Object.is, men är inte exakt densamma. Object.is(+0, -0) returnerar false, men i ett Set räknas de som identiska. Observera denna skillnad.

Vanligt användningsområde: Mängdoperationer (union, snitt, differens)

Mängdoperationer kan skrivas tydligare med hjälp av Set. Nedan är vanliga implementations-exempel.

Här är exempel på funktioner för union, intersection och 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]
  • Mängdoperationer kan skrivas enkelt genom att använda filter i kombination med Set och arrayer. Vid hantering av stora datamängder ger O(1) prestanda för has snabbare operationer.

Praktiskt exempel: Hitta skillnader mellan arrayer (upptäckta tillagda/borttagna poster)

Följande exempel visar hur du kan använda ett Set för att hitta skillnaden mellan två arrayer (en gammal och en ny lista). Detta gör det möjligt att identifiera vilka element som har lagts till och vilka som har tagits bort.

 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] }
  • Denna metod är mycket praktisk för att upptäcka skillnader i ID-listor, tagglistor och liknande situationer. Det är enklast att använda med primitiva värden.

Skillnader mellan WeakSet och Set (minneshantering)

WeakSet liknar Set, men den använder svaga referenser vilket gör att dess objekt kan garbage-samlas (tas bort automatiskt). Följande visar grundläggande användning av WeakSet.

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 endast innehålla objekt och kan inte itereras över. Nedan är exempel på begränsningarna för WeakSet—det innehåller bara objekt och kan inte itereras över.

 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 är användbart för att tillfälligt hålla koll på förekomsten av objekt, men du kan inte räkna upp dess element eller ta reda på dess storlek.

Prestanda och hur man väljer när man ska använda

När du bestämmer dig för om du ska använda ett Set är det viktigt att förstå dess prestanda och datans natur.

  • has, add och delete fungerar i genomsnitt med nästan O(1)-prestanda. Därför är Set ofta mer fördelaktigt än arrayer vid frekventa existenskontroller eller borttagning av dubbletter.
  • Var försiktig om du vill ta bort dubbletter av objekt baserat på deras innehåll (värden). Eftersom Set jämför med referenser är ett praktiskt sätt att använda ID:n eller andra nycklar, eller att serialisera objekt till primitiva värden innan du använder Sets om du behöver jämföra baserat på värde.
  • Set är särskilt användbart för att förbättra kodläsbarheten för små till medelstora samlingar. Å andra sidan, om du hanterar ett mycket stort antal element eller ofta konverterar mellan arrayer och Set, rekommenderas det att faktiskt mäta prestanda och testa.

Vanliga fallgropar

Set är bekvämt, men om du inte känner till dess specifikationer kan du bli förvirrad av oväntat beteende. Här är några typiska saker att vara uppmärksam på:.

  • Objekt jämförs med referenser, så även om innehållet är detsamma, räknas olika objekt inte som dubbletter.
  • Set behåller insättningsordningen, men du kan inte komma åt element med index som med arrayer. Om du vill använda indexbaserad åtkomst, konvertera först Set till en array.
  • WeakSet kan inte enumreras och kan bara lagra objekt. Observera att dess användningsområden är begränsade.
  • NaN behandlas som samma värde, och +0 och -0 särskiljs inte. Detta beror på jämförelseregeln Same-value-zero.

Sammanfattning

Set är en bekväm datastruktur som låter dig hantera samlingar av unika värden på ett intuitivt sätt. Du kan använda det för att ta bort dubbletter från arrayer, göra snabba existenskontroller eller implementera mängdoperationer som union och snitt med enkel och läsbar kod.

Å andra sidan, eftersom objekt jämförs med referenser, krävs extra åtgärder om du vill avgöra likhet baserat på deras innehåll.

Genom att förstå dessa egenskaper och använda dem rätt blir Set ett kraftfullt val för att förbättra kodens läsbarhet och underhållbarhet.

Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.

YouTube Video