Oggetto `Set`
Questo articolo spiega l'oggetto Set.
Spiegheremo l'oggetto Set con esempi pratici.
YouTube Video
Oggetto Set
Set è un oggetto integrato utilizzato per gestire collezioni di valori unici, senza duplicati. Permette di scrivere più facilmente l'eliminazione dei duplicati e il controllo dell'esistenza rispetto agli array e rende più semplice l'implementazione di operazioni insiemistiche come unione e intersezione.
Basi: Creazione e utilizzo dei Set
Innanzitutto, vediamo come creare un Set, aggiungere e rimuovere elementi, controllare l'esistenza e ottenerne la dimensione.
Di seguito è riportato un modello base che crea un nuovo Set e mostra l'uso di add, has, delete e 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]
- Come mostrato in questo codice,
Setrimuove automaticamente i valori primitivi duplicati e puoi ottenere il numero di elementi usandosize.
Metodi di iterazione
Set è iterabile, quindi puoi scorrerlo usando for...of oppure forEach. L'ordine è l'ordine di inserimento.
Ecco i modi tipici per utilizzare for...of e 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});- La firma del callback per
forEachèvalue, value, set(per compatibilità con Map), ma in pratica di solito serve solo il primo argomentovalue.
Conversione tra Array e Set (utile per rimuovere i duplicati)
Qui mostriamo una tecnica semplice per rimuovere i duplicati da un array e come convertire un Set nuovamente in un array.
Di seguito è riportato un esempio di rimozione dei duplicati da un array passandolo attraverso un 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]
- Questo schema è breve e veloce, quindi viene spesso usato per rimuovere i duplicati negli array. È particolarmente efficace per i valori primitivi.
Oggetti e gestione dei riferimenti
Gli oggetti in un Set vengono confrontati per riferimento, quindi diverse istanze con lo stesso contenuto vengono considerate elementi distinti.
Il codice qui sotto mostra cosa succede quando si aggiungono oggetti a un 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)
- La rilevazione dei duplicati per gli oggetti si basa sull'identità di riferimento, quindi se vuoi deduplicare in base solo al contenuto degli oggetti, dovrai serializzarli o elaborarli in altro modo.
Valori speciali: Gestione di NaN e -0/+0
Set utilizza la regola di confronto Same-value-zero per determinare l'uguaglianza dei valori. Questo metodo di confronto presenta le seguenti caratteristiche riguardo ai numeri:.
NaNè considerato uguale aNaN.+0positivo e-0negativo non sono distinti e vengono trattati come lo stesso valore.
Pertanto, quando aggiungi questi valori a un Set, si verifica il seguente comportamento:.
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)
- Nella comparazione normale (
NaN === NaN) restituiscefalse, ma all'interno di unSettutti i variNaNvengono considerati 'lo stesso valore'. - +0 e -0 possono essere distinti matematicamente, ma in un
Setvengono semplicemente trattati come0. - Di conseguenza, solo un
NaNe uno0rimangono all'interno delSet. - La regola di confronto di
Setè simile aObject.is, ma non è esattamente la stessa.Object.is(+0, -0)restituiscefalse, ma in unSetvengono considerati identici. Tieni presente questa differenza.
Utilità comuni: Operazioni su Set (Unione, Intersezione, Differenza)
Le operazioni su insiemi possono essere scritte in modo più chiaro usando i Set. Di seguito sono riportati alcuni esempi tipici di implementazione.
Ecco alcuni esempi di funzioni per unione, intersezione e differenza.
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]
- Le operazioni su insiemi possono essere scritte semplicemente usando i filtri combinando
Sete array. Quando si gestiscono grandi quantità di dati, la performance O(1) dihasrende le operazioni più veloci.
Esempio pratico: Trovare le differenze tra array (individuare elementi aggiunti/rimossi)
L'esempio seguente mostra come utilizzare un Set per trovare la differenza tra due array (una vecchia lista e una nuova lista). Questo ti permette di identificare quali elementi sono stati aggiunti e quali rimossi.
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] }
- Questo metodo è molto comodo per rilevare differenze in liste di ID, liste di tag e situazioni simili. È più semplice da utilizzare con valori primitivi.
Differenze tra WeakSet e Set (Gestione della memoria)
WeakSet è simile a Set, ma utilizza riferimenti deboli, permettendo agli oggetti al suo interno di essere raccolti dal garbage collector. Qui di seguito vengono mostrati gli utilizzi di base di 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 può contenere solo oggetti e non può essere iterato. Di seguito sono riportati esempi dei limiti di WeakSet—contiene solo oggetti e non può essere iterato.
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è utile per tracciare temporaneamente la presenza di oggetti, ma non puoi enumerare i suoi elementi o ottenerne la dimensione.
Prestazioni e scelta dell'utilizzo
Quando si decide se utilizzare un Set, è importante comprendere le sue caratteristiche prestazionali e la natura dei dati.
has,addedeletedi solito operano con una prestazione media quasi O(1). Pertanto, in scenari in cui controlli frequentemente l'esistenza o rimuovi i duplicati,Setè spesso più vantaggioso rispetto agli array.- Fai attenzione se vuoi deduplicare oggetti in base al loro contenuto (valori). Poiché
Setconfronta per riferimento, un approccio pratico consiste nell'usare ID o altre chiavi, oppure serializzare gli oggetti in valori primitivi prima di usare i Set quando è necessario il confronto sui valori. Setè particolarmente utile per migliorare la leggibilità del codice con collezioni di piccole o medie dimensioni. D'altra parte, se gestisci un numero molto elevato di elementi o effettui frequenti conversioni tra array e Set, è consigliato eseguire realmente benchmark e test.
Errori comuni
Set è conveniente, ma se non conosci le sue specifiche potresti essere sorpreso da comportamenti inaspettati. Ecco alcuni punti tipici a cui prestare attenzione:.
- Gli oggetti vengono confrontati per riferimento, quindi anche se il loro contenuto è uguale, oggetti diversi non sono considerati duplicati.
Setmantiene l'ordine di inserimento, ma non puoi accedere agli elementi tramite indice come negli array. Se vuoi usare l'accesso tramite indice, converti prima ilSetin un array.WeakSetnon può essere enumerato e può contenere solo oggetti. Nota che le sue applicazioni sono limitate.NaNviene trattato come lo stesso valore e+0e-0non vengono distinti. Questo è dovuto alla regola di confronto Same-value-zero.
Riepilogo
Set è una struttura dati comoda che permette di gestire collezioni di valori unici in modo intuitivo. Puoi usarlo per rimuovere duplicati da array, effettuare controlli rapidi di esistenza o implementare operazioni su insiemi come unione e intersezione con codice semplice e leggibile.
D'altra parte, poiché gli oggetti vengono confrontati per riferimento, sono necessarie misure aggiuntive se si vuole valutare l'uguaglianza in base al loro contenuto.
Comprendendo queste caratteristiche e usandole in modo appropriato, Set diventa una scelta potente per migliorare la leggibilità e la manutenibilità del codice.
Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.