`Set`-objekt

Denne artikkelen forklarer Set-objektet.

Vi vil forklare Set-objektet med praktiske eksempler.

YouTube Video

Set-objekt

Set er et innebygd objekt brukt til å håndtere samlinger av unike, ikke-dupliserte verdier. Det lar deg utføre fjerning av duplikater og eksistenssjekk enklere enn med arrayer, og gjør det lettere å implementere mengdeoperasjoner som union og snitt.

Grunnleggende: Lage og bruke Set

Først skal vi se på hvordan man lager et Set, legger til og fjerner elementer, sjekker for eksistens, og finner størrelsen.

Nedenfor er et grunnleggende mønster som lager et nytt Set og demonstrerer bruk av add, has, delete og 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 vist i denne koden, fjerner Set automatisk dupliserte primitive verdier, og du kan få antall elementer ved å bruke size.

Iterasjonsmetoder

Set er itererbar, så du kan gå gjennom den med for...of eller forEach. Rekkefølgen er den samme som innsettingsrekkefølgen.

Her er typiske måter å bruke for...of og forEach på.

 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});
  • Callback-signaturen for forEach er value, value, set (for kompatibilitet med Map), men i praksis trenger du vanligvis kun det første value-argumentet.

Konvertering mellom arrayer og Set (nyttig for å fjerne duplikater)

Her viser vi en enkel teknikk for å fjerne duplikater fra en array og hvordan du konverterer et Set tilbake til en array.

Nedenfor er et eksempel på å fjerne duplikater fra en array ved å føre den gjennom et 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]
  • Dette mønsteret er kort og raskt, så det brukes ofte for å fjerne duplikater fra arrayer. Det er spesielt effektivt for primitive verdier.

Objekter og referansehåndtering

Objekter i et Set sammenlignes på referanse, så forskjellige instanser med samme innhold behandles som separate elementer.

Koden nedenfor demonstrerer hva som skjer når du legger til objekter i et 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)
  • Duplikatdeteksjon for objekter er basert på referanseidentitet, så hvis du vil fjerne duplikater basert på objektinnhold alene, må du serialisere eller på annen måte behandle dem.

Spesielle verdier: Håndtering av NaN og -0/+0

Set bruker Same-value-zero-sammenligningsregelen for å bestemme likhet mellom verdier. Denne sammenligningsmetoden har følgende egenskaper med hensyn til tall:.

  • NaN regnes som lik NaN.
  • Positiv +0 og negativ -0 skilles ikke, og behandles som samme verdi.

Derfor, når du legger til disse verdiene i et Set, oppstår følgende oppførsel:.

 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)
  • Ved vanlig sammenligning (NaN === NaN) får du false, men i et Set regnes alle NaN-verdier som 'samme verdi'.
  • +0 og -0 kan skilles matematisk, men i et Set blir de bare behandlet som 0.
  • Som resultat forblir kun én NaN og én 0 i Set.
  • Sammenligningsregelen for Set ligner på Object.is, men er ikke helt den samme. Object.is(+0, -0) returnerer false, men i et Set anses de som identiske. Vennligst merk deg denne forskjellen.

Vanlige verktøy: Mengdeoperasjoner (union, snitt, differanse)

Mengdeoperasjoner kan skrives tydeligere ved bruk av Set. Nedenfor er vanlige implementeringseksempler.

Her er eksempler på funksjoner for union, intersection og 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]
  • Mengdeoperasjoner kan enkelt skrives ved å bruke filterfunksjoner med en kombinasjon av Set og arrayer. Når man jobber med store datasett, gjør O(1)-ytelsen til has operasjoner raskere.

Praktisk eksempel: Finne forskjeller mellom arrayer (oppdage tilføyde/fjernede elementer)

Eksempelet nedenfor viser hvordan man bruker et Set for å finne forskjellen mellom to arrayer (en gammel liste og en ny liste). Dette lar deg identifisere hvilke elementer som ble lagt til og hvilke som ble fjernet.

 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] }
  • Denne metoden er svært praktisk for å oppdage forskjeller i ID-lister, tag-lister og lignende situasjoner. Det er enklest å bruke med primitive verdier.

Forskjeller mellom WeakSet og Set (minnehåndtering)

WeakSet ligner på Set, men bruker svake referanser, noe som gjør at elementene kan samles inn av søppeloppsamleren. Nedenfor demonstreres grunnleggende bruk 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 kun inneholde objekter og kan ikke itereres over. Nedenfor er eksempler på begrensningene til WeakSet – det kan bare inneholde objekter, og kan ikke itereres over.

 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 er nyttig for midlertidig sporing av objekters tilstedeværelse, men du kan hverken enumerere elementene eller finne størrelsen.

Ytelse og valg av bruk

Når du vurderer om du skal bruke et Set, er det viktig å forstå ytelsesegenskapene og typen data du har.

  • has, add og delete kjører vanligvis i nær O(1) ytelse i gjennomsnitt. Derfor er Set ofte mer fordelaktig enn arrayer i scenarioer hvor du ofte sjekker for eksistens eller fjerner duplikater.
  • Vær obs hvis du ønsker å fjerne duplikater på grunnlag av objektenes innhold (verdier). Siden Set sammenligner etter referanse, er en praktisk løsning å bruke ID-er eller andre nøkler, eller serialisere objektene til primitive verdier før du bruker Set, når verdibasert sammenligning er nødvendig.
  • Set er spesielt nyttig for å forbedre lesbarheten av kode for små til middels store samlinger. På den annen side, hvis du jobber med svært mange elementer eller ofte konverterer mellom arrayer og Set, anbefales det å benchmarke og teste faktisk.

Vanlige fallgruver

Set er praktisk, men hvis du ikke kjenner til spesifikasjonene, kan du bli overrasket over uventet oppførsel. Her er noen typiske ting du bør passe på:.

  • Objekter blir sammenlignet etter referanse, så selv om innholdet er det samme regnes ulike objekter ikke som duplikater.
  • Set bevarer innsettingsrekkefølgen, men du kan ikke få tilgang til elementer med indeks slik du kan med arrayer. Hvis du vil bruke indekser-basert tilgang, konverter først Set til en array.
  • WeakSet kan ikke enumreres og kan kun lagre objekter. Merk at bruksområdene er begrenset.
  • NaN behandles som samme verdi, og +0 og -0 skilles ikke. Dette skyldes Same-value-zero-sammenligningsregelen.

Sammendrag

Set er en praktisk datastruktur som lar deg håndtere samlinger av unike verdier på en intuitiv måte. Du kan bruke det for å fjerne duplikater fra arrayer, gjøre raske eksistenssjekker eller implementere mengdeoperasjoner som union og snitt med enkel og lesbar kode.

På den annen side, siden objekter sammenlignes på referanse, er ekstra tiltak nødvendige hvis du vil sammenligne basert på innholdet deres.

Ved å forstå disse egenskapene og bruke dem riktig, blir Set et kraftig valg for å bedre kode-lesbarhet og vedlikeholdbarhet.

Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.

YouTube Video