Ottieni tutti i valori univoci in un array JavaScript (rimuovi i duplicati)

Ho una serie di numeri che ho bisogno per assicurarmi che siano unici. Ho trovato il frammento di codice qui sotto su Internet e funziona benissimo finché l’array non ha zero in esso. Ho trovato questo altro script qui su SO che sembra quasi esattamente come esso, ma non fallisce.

Quindi, per il piacere di aiutarmi a imparare, qualcuno può aiutarmi a determinare dove lo script del prototipo sta andando male?

Array.prototype.getUnique = function() { var o = {}, a = [], i, e; for (i = 0; e = this[i]; i++) {o[e] = 1}; for (e in o) {a.push (e)}; return a; } 

Altre risposte dalla domanda duplicata:

  • Rimuovi i duplicati dalla matrice JavaScript

Domanda simile:

  • Ottieni tutti i valori con più di un’occorrenza (es: non unica) in una matrice

Con JavaScript 1.6 / ECMAScript 5 è ansible utilizzare il metodo di filter nativo di una matrice nel seguente modo per ottenere un array con valori univoci:

 function onlyUnique(value, index, self) { return self.indexOf(value) === index; } // usage example: var a = ['a', 1, 'a', 2, '1']; var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1'] 

Il filter metodo nativo eseguirà il ciclo attraverso la matrice e lascerà solo quelle voci che passano solo alla funzione di callback onlyUnique .

onlyUnique controlli onlyUnique , se il valore dato è il primo che si verifica. In caso contrario, deve essere un duplicato e non verrà copiato.

Questa soluzione funziona senza alcuna libreria aggiuntiva come jQuery o prototype.js.

Funziona anche per gli array con tipi di valore misto.

Per i browser precedenti (filter metodi nativi e indexOf è ansible trovare soluzioni nella documentazione MDN per filtro e indexOf .

Se si desidera mantenere l’ultima occorrenza di un valore, sostituire semplicemente lastIndexOf con lastIndexOf .

Con ES6 potrebbe essere ridotto a questo:

 // usage example: var myArray = ['a', 1, 'a', 2, '1']; var unique = myArray.filter((v, i, a) => a.indexOf(v) === i); // unique is ['a', 1, 2, '1'] 

Grazie a Camilo Martin per il suggerimento nel commento.

ES6 ha un object nativo Set per memorizzare valori univoci. Per ottenere un array con valori unici, puoi farlo ora:

 var myArray = ['a', 1, 'a', 2, '1']; let unique = [...new Set(myArray)]; // unique is ['a', 1, 2, '1'] 

Il costruttore di Set prende un object iterabile, come Array, e l’operatore di spread ... trasforma l’insieme in una matrice. Grazie a Lukas Liese per il suggerimento nel commento.

Risposta aggiornata per ES6 / ES2015 : utilizzando il Set , la soluzione a linea singola è:

 var items = [4,5,4,6,3,4,5,2,23,1,4,4,4] var uniqueItems = Array.from(new Set(items)) 

Che ritorna

 [4, 5, 6, 3, 2, 23, 1] 

Come suggerito da le_m , questo può anche essere abbreviato usando l’ operatore di spread , come

 var uniqueItems = [...new Set(items)] 

Puoi anche usare underscore.js .

 console.log(_.uniq([1, 2, 1, 3, 1, 4])); 
  

Mi rendo conto che questa domanda ha già più di 30 risposte. Ma ho letto prima tutte le risposte esistenti e ho fatto le mie ricerche.

Ho diviso tutte le risposte a 4 possibili soluzioni:

  1. Usa la nuova funzione ES6: [...new Set( [1, 1, 2] )];
  2. Usa l’object { } per evitare duplicati
  3. Usa l’array helper [ ]
  4. Usa filter + indexOf

Ecco i codici di esempio trovati nelle risposte:

Usa la nuova funzione ES6: [...new Set( [1, 1, 2] )];

 function uniqueArray0(array) { var result = Array.from(new Set(array)); return result } 

Usa l’object { } per evitare duplicati

 function uniqueArray1( ar ) { var j = {}; ar.forEach( function(v) { j[v+ '::' + typeof v] = v; }); return Object.keys(j).map(function(v){ return j[v]; }); } 

Usa l’array helper [ ]

 function uniqueArray2(arr) { var a = []; for (var i=0, l=arr.length; i 

Usa filter + indexOf

 function uniqueArray3(a) { function onlyUnique(value, index, self) { return self.indexOf(value) === index; } // usage var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1'] return unique; } 

E mi sono chiesto quale sia più veloce. Ho creato un esempio di Google Sheet per testare le funzioni. Nota: ECMA 6 non è disponibile in Fogli Google, quindi non posso verificarlo.

Ecco il risultato dei test: inserisci la descrizione dell'immagine qui

Mi aspettavo di vedere che il codice che utilizza object { } vincerà perché usa l'hash. Quindi sono contento che i test abbiano mostrato i migliori risultati per questo algoritmo in Chrome e IE. Grazie a @rab per il codice .

Da allora ho trovato un buon metodo che usa jQuery

 arr = $.grep(arr, function(v, k){ return $.inArray(v ,arr) === k; }); 

Nota: questo codice è stato estratto dal post di punzonatura delle anatre di Paul Irish – Ho dimenticato di dare credito: P

One Liner, Pure JavaScript

Con syntax ES6

list = list.filter((x, i, a) => a.indexOf(x) == i)

 x --> item in array i --> index of item a --> array reference, (in this case "list") 

inserisci la descrizione dell'immagine qui

Con syntax ES5

 list = list.filter(function (x, i, a) { return a.indexOf(x) == i; }); 

Compatibilità del browser : IE9 +

La soluzione più corta con ES6: [...new Set( [1, 1, 2] )];

O se vuoi modificare il prototipo di Array (come nella domanda originale):

 Array.prototype.getUnique = function() { return [...new Set( [this] )]; }; 

EcmaScript 6 è solo parzialmente implementato nei browser moderni al momento (agosto 2015), ma Babel è diventato molto popolare per il trasferimento di ES6 (e anche ES7) in ES5. In questo modo puoi scrivere il codice ES6 oggi!

Se ti stai chiedendo cosa significa ... , si chiama operatore di spread . Da MDN : «L’operatore di spread consente di espandere un’espressione in luoghi in cui sono previsti più argomenti (per chiamate di funzione) o più elementi (per letterali di array)». Poiché un Set è un iterabile (e può avere solo valori univoci), l’operatore di spread espanderà il Set per riempire l’array.

Risorse per l’apprendimento di ES6:

  • Esplorando ES6 del Dr. Axel Rauschmayer
  • Cerca “ES6” dalle newsletter settimanali di JS
  • ES6 articoli approfonditi dal blog di Mozilla Hacks

La soluzione più semplice:

 var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1]; console.log([...new Set(arr)]); 

Il modo più semplice e veloce (in Chrome) di farlo:

 Array.prototype.unique = function() { var a = []; for (var i=0, l=this.length; i 

Passa semplicemente attraverso ogni elemento dell'array, verifica se quell'elemento è già presente nell'elenco e, in caso contrario, passa alla matrice che viene restituita.

Secondo jsPerf, questa funzione è la più veloce di quelle che potrei trovare ovunque - sentiti libero di aggiungere il tuo.

La versione non prototipo:

 function uniques(arr) { var a = []; for (var i=0, l=arr.length; i 

Ordinamento

Quando è anche necessario ordinare l'array, quanto segue è il più veloce:

 Array.prototype.sortUnique = function() { this.sort(); var last_i; for (var i=0;i 

o non prototipo:

 function sortUnique(arr) { arr.sort(); var last_i; for (var i=0;i 

Questo è anche più veloce del metodo sopra descritto nella maggior parte dei browser non Chrome.

SOLO PERFORMANCE! questo codice è probabilmente 10 volte più veloce di tutti i codici qui * funziona su tutti i browser e ha anche il minor impatto sulla memoria …. e altro ancora

se non hai bisogno di riutilizzare il vecchio array, btw fai le altre operazioni necessarie prima di convertirlo in univoco qui è probabilmente il modo più veloce per farlo, anche molto breve.

 var array=[1,2,3,4,5,6,7,8,9,0,1,2,1]; 

allora puoi provare questo

 var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1]; function toUnique(a, b, c) { //array,placeholder,placeholder b = a.length; while (c = --b) while (c--) a[b] !== a[c] || a.splice(c, 1); return a // not needed ;) } console.log(toUnique(array)); //[3, 4, 5, 6, 7, 8, 9, 0, 2, 1] 

Molte delle risposte qui potrebbero non essere utili ai principianti. Se il de-duplicazione di un array è difficile, conosceranno davvero la catena del prototipo o persino jQuery?

Nei browser moderni, una soluzione semplice e pulita è quella di archiviare i dati in un Set , progettato per essere un elenco di valori univoci.

 const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford']; const uniqueCars = Array.from(new Set(cars)); 

Array.from è utile per convertire il set in array in modo da avere un facile accesso a tutti i fantastici metodi (caratteristiche) di cui dispongono gli array. Ci sono anche altri modi per fare la stessa cosa. Ma potrebbe non essere necessario Array.from , in quanto i set hanno un sacco di funzioni utili come forEach .

Se è necessario supportare il vecchio Internet Explorer e quindi non è ansible utilizzare Set, una tecnica semplice consiste nel copiare gli elementi in un nuovo array mentre si controlla in anticipo se sono già nel nuovo array.

 // Create a list of cars, with duplicates. var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford']; // Create a list of unique cars, to put a car in if we haven't already. var uniqueCars = []; // Go through each car, one at a time. cars.forEach(function (car) { // The code within the following block runs only if the // current car does NOT exist in the uniqueCars list // - aka prevent duplicates if (uniqueCars.indexOf(car) === -1) { // Since we now know we haven't seen this car before, // copy it to the end of the uniqueCars list. uniqueCars.push(car); } }); 

Per renderlo immediatamente riutilizzabile, mettiamolo in una funzione.

 function deduplicate(data) { if (data.length > 0) { var result = []; data.forEach(function (elem) { if (result.indexOf(elem) === -1) { result.push(elem); } }); return result; } } 

Quindi per sbarazzarci dei duplicati, ora lo faremo.

 var uniqueCars = deduplicate(cars); 

La parte deduplicate(cars) diventa la cosa che abbiamo chiamato risultato al termine della funzione.

Basta passargli il nome di qualsiasi array che ti piace.

Questo prototipo di getUnique non è completamente corretto, perché se ho un array come: ["1",1,2,3,4,1,"foo"] restituirà ["1","2","3","4"] e "1" è una stringa e 1 è un numero intero; sono diversi.

Ecco una soluzione corretta:

 Array.prototype.unique = function(a){ return function(){ return this.filter(a) } }(function(a,b,c){ return c.indexOf(a,b+1) < 0 }); 

utilizzando:

 var foo; foo = ["1",1,2,3,4,1,"foo"]; foo.unique(); 

Quanto sopra produrrà ["1",2,3,4,1,"foo"] .

 ["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) { return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev; }, []); [0,1,2,0,3,2,1,5].reduce(function(prev, cur) { return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev; }, []); 

Senza estendere Array.prototype (si dice che sia una ctriggers pratica) o usando jquery / underscore, puoi semplicemente filter l’array.

Mantenendo l’ultima occorrenza:

  function arrayLastUnique(array) { return array.filter(function (a, b, c) { // keeps last occurrence return c.indexOf(a, b + 1) < 0; }); }, 

o prima occorrenza:

  function arrayFirstUnique(array) { return array.filter(function (a, b, c) { // keeps first occurrence return c.indexOf(a) === b; }); }, 

Beh, è ​​solo javascript ECMAScript 5+, che significa solo IE9 +, ma è bello per uno sviluppo in HTML / JS nativo (Windows Store App, Firefox OS, Sencha, PhoneGap, Titanium, ...).

Questo perché 0 è un valore falsy in JavaScript.

this[i] sarà falsato se il valore dell’array è 0 o qualsiasi altro valore di falsy.

Se stai usando il framework Prototype non è necessario fare cicli “for”, puoi usare http://www.prototypejs.org/api/array/uniq in questo modo:

 var a = Array.uniq(); 

Che produrrà un array duplicato senza duplicati. Mi sono imbattuto nella tua domanda alla ricerca di un metodo per contare distinti record di array così dopo

uniq ()

ero solito

dimensione()

e c’era il mio semplice risultato. ps Scusa se ho sbagliato a scrivere qualcosa

edit: se vuoi sfuggire ai record non definiti che potresti voler aggiungere

compatto()

prima, in questo modo:

 var a = Array.compact().uniq(); 
 Array.prototype.getUnique = function() { var o = {}, a = [] for (var i = 0; i < this.length; i++) o[this[i]] = 1 for (var e in o) a.push(e) return a } 

Non sono sicuro del motivo per cui Gabriel Silveira ha scritto la funzione in questo modo, ma una forma più semplice che funziona per me altrettanto bene e senza la minificazione è:

 Array.prototype.unique = function() { return this.filter(function(value, index, array) { return array.indexOf(value, index + 1) < 0; }); }; 

o in CoffeeScript:

 Array.prototype.unique = -> this.filter( (value, index, array) -> array.indexOf(value, index + 1) < 0 ) 

con es6 (e mantiene l’ordine):

 [...new Set(myArray)]; 

Crea un set dell’array e quindi inizializza la copia superficiale del set nel contenitore desiderato.

 let array = [1,2,3,2,1]; let uniqueArray = [... new Set(array)]; 

Dal blog di Shamasis Bhattacharya (complessità temporale O (2n)):

 Array.prototype.unique = function() { var o = {}, i, l = this.length, r = []; for(i=0; i 

Dal blog di Paul Irish : miglioramento su JQuery. .unique() :

 (function($){ var _old = $.unique; $.unique = function(arr){ // do the default behavior only if we got an array of elements if (!!arr[0].nodeType){ return _old.apply(this,arguments); } else { // reduce the array to contain no dupes via grep/inArray return $.grep(arr,function(v,k){ return $.inArray(v,arr) === k; }); } }; })(jQuery); // in use.. var arr = ['first',7,true,2,7,true,'last','last']; $.unique(arr); // ["first", 7, true, 2, "last"] var arr = [1,2,3,4,5,4,3,2,1]; $.unique(arr); // [1, 2, 3, 4, 5] 

Ricerca di valori di array univoci in un metodo semplice

 function arrUnique(a){ var t = []; for(var x = 0; x < a.length; x++){ if(t.indexOf(a[x]) == -1)t.push(a[x]); } return t; } arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9] 

Per risolvere il problema al contrario, potrebbe essere utile non avere duplicati mentre si carica l’array, il modo in cui l’object Set lo farebbe ma non è ancora disponibile in tutti i browser. Salva la memoria ed è più efficiente se hai bisogno di guardare il suo contenuto molte volte.

 Array.prototype.add = function (elem) { if (this.indexOf(elem) == -1) { this.push(elem); } } 

Campione:

 set = []; [1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); }); 

Ti dà set = [1,3,4,2]

strano questo non è stato suggerito prima .. per rimuovere i duplicati dalla chiave object ( id sotto) in un array si può fare qualcosa di simile a questo:

 const uniqArray = array.filter((obj, idx, arr) => ( arr.findIndex((o) => o.id === obj.id) === idx )) 

C’è un modo semplice per risolvere questa attività tramite ES6 – utilizzando Set:

 let arr = [1, 1, 2, 2, 3, 3]; let deduped = [...new Set(arr)] // [1, 2, 3] 

Puoi anche usare jQuery

 var a = [1,5,1,6,4,5,2,5,4,3,1,2,6,6,3,3,2,4]; // note: jQuery's filter params are opposite of javascript's native implementation :( var unique = $.makeArray($(a).filter(function(i,itm){ // note: 'index', not 'indexOf' return i == $(a).index(itm); })); // unique: [1, 5, 6, 4, 2, 3] 

Originariamente risposto a: funzione jQuery per ottenere tutti gli elementi univoci da un array?

Se qualcuno usa knockoutjs

 ko.utils.arrayGetDistinctValues() 

BTW ha dato un’occhiata a tutti i ko.utils.array* utilità ko.utils.array* .

Ho scoperto che serializzare la loro chiave hash mi ha aiutato a farlo funzionare per gli oggetti.

 Array.prototype.getUnique = function() { var hash = {}, result = [], key; for ( var i = 0, l = this.length; i < l; ++i ) { key = JSON.stringify(this[i]); if ( !hash.hasOwnProperty(key) ) { hash[key] = true; result.push(this[i]); } } return result; } 

Puoi anche usare sugar.js:

 [1,2,2,3,1].unique() // => [1,2,3] [{id:5, name:"Jay"}, {id:6, name:"Jay"}, {id: 5, name:"Jay"}].unique('id') // => [{id:5, name:"Jay"}, {id:6, name:"Jay"}] 

Possiamo farlo usando i set ES6:

 var duplicatedArray = [1,2,3,4,5,1,1,1,2,3,4]; var uniqueArray = Array.from(new Set(duplicatedArray)); 

// L’output sarà

 uniqueArray = [1,2,3,4,5];