Rimuovere i valori duplicati dall'array JS
Ho un array JavaScript molto semplice che può contenere o meno duplicati.
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
Ho bisogno di rimuovere i duplicati e mettere i valori unici in un nuovo array.
Potrei indicare tutti i codici che ho provato ma penso che sia inutile perché non funzionano. Accetto anche soluzioni jQuery.
Domanda simile:
1217
3
TL;DR
Usando il costruttore Set e la sintassi di diffusione:
Intelligente" ma naïvia
Fondamentalmente, iteriamo sull'array e, per ogni elemento, controlliamo se la prima posizione di questo elemento nell'array è uguale alla posizione corrente. Ovviamente, queste due posizioni sono diverse per gli elementi duplicati. Usando il terzo ("questo array") parametro della callback del filtro possiamo evitare una chiusura della variabile array:
Anche se conciso, questo algoritmo non è particolarmente efficiente per array di grandi dimensioni (tempo quadratico). Hashtables in soccorso
Questo è il modo in cui viene fatto di solito. L'idea è di mettere ogni elemento in una hashtable e poi controllare la sua presenza istantaneamente. Questo ci dà un tempo lineare, ma ha almeno due svantaggi:
uniq([1,"1"])
restituirà solo[1]
per la stessa ragione, tutti gli oggetti saranno considerati uguali:
uniq([{foo:1},{foo:2}])
restituirà solo[{foo:1}]
. Detto questo, se i vostri array contengono solo primitive e non vi importa dei tipi (ad esempio sono sempre numeri), questa soluzione è ottimale. Il meglio di due mondiUna soluzione universale combina entrambi gli approcci: usa gli hash lookup per le primitive e la ricerca lineare per gli oggetti.
sort | uniq
Un'altra opzione è quella di ordinare prima l'array, e poi rimuovere ogni elemento uguale al precedente:
Di nuovo, questo non funziona con gli oggetti (perché tutti gli oggetti sono uguali per
sort
). Inoltre, cambiamo silenziosamente l'array originale come effetto collaterale - non va bene! Tuttavia, se il vostro input è già ordinato, questa è la strada da seguire (basta rimuoveresort
da quanto sopra). Unico da...A volte si desidera unificare una lista in base a qualche criterio diverso dalla semplice uguaglianza, per esempio, per filtrare gli oggetti che sono diversi, ma condividono qualche proprietà. Questo può essere fatto elegantemente passando un callback. Questo "key" callback viene applicato ad ogni elemento, e gli elementi con "key" uguali vengono rimossi. Poiché ci si aspetta che
chiave
restituisca una primitiva, la tabella hash funzionerà bene qui:Una
chiave()
particolarmente utile èJSON.stringify
che rimuoverà oggetti che sono fisicamente diversi, ma "sembrano" uguali:Se la
chiave
non è primitiva, devi ricorrere alla ricerca lineare:In ES6 si può usare un
Set
:o una
Mappa
:che funzionano entrambe anche con chiavi non primitive. Prima o ultima?
Quando si rimuovono oggetti da una chiave, si potrebbe voler mantenere il primo degli oggetti "uguali" o l'ultimo. Usate la variante
Set
sopra per mantenere il primo, e laMap
per mantenere l'ultimo:Biblioteche
Sia underscore che Lo-Dash forniscono i metodi
uniq
. I loro algoritmi sono fondamentalmente simili al primo snippet sopra e si riducono a questo:Questo è quadratico, ma ci sono belle chicche aggiuntive, come il wrapping nativo
indexOf
, la capacità di uniqificare per una chiave (iteratee
nel loro linguaggio), e le ottimizzazioni per gli array già ordinati. Se stai usando jQuery e non puoi sopportare nulla senza un dollaro prima, fa così:che è, di nuovo, una variazione del primo snippet. Prestazioni
Le chiamate di funzione sono costose in JavaScript, quindi le soluzioni di cui sopra, per quanto concise, non sono particolarmente efficienti. Per ottenere le massime prestazioni, sostituire il
filtro
con un ciclo e sbarazzarsi delle altre chiamate di funzione:Questo pezzo di codice brutto fa la stessa cosa dello snippet #3 sopra, ma un ordine di grandezza più veloce (al 2017 è solo due volte più veloce - quelli del nucleo JS stanno facendo un gran lavoro!)
ES6
ES6 fornisce l'oggetto Set, che rende le cose molto più facili:
o
Si noti che, a differenza di python, i set ES6 sono iterati in ordine di inserimento, quindi questo codice conserva l'ordine dell'array originale. Tuttavia, se avete bisogno di un array con elementi unici, perché non usare gli insiemi fin dall'inizio? Generatori
Una versione "pigra", basata su generatori, di
uniq
può essere costruita sulla stessa base:Veloce e sporco usando jQuery:
Vanilla JS: rimuovere i duplicati usando un oggetto come un set
Potete sempre provare a metterlo in un oggetto e poi iterare attraverso le sue chiavi:
Vanilla JS: Rimuovere i duplicati tracciando i valori già visti (order-safe)
Oppure, per una versione order-safe, usare un oggetto per memorizzare tutti i valori visti in precedenza, e controllare i valori rispetto ad esso prima di aggiungerli ad un array.
ECMAScript 6: Utilizzare la nuova struttura dati Set (order-safe)
ECMAScript 6 aggiunge la nuova struttura dati
Set
, che permette di memorizzare valori di qualsiasi tipo.Set.values
restituisce elementi in ordine di inserimento.Esempio d'uso: