Obtenga todos los valores únicos en una matriz de JavaScript (eliminar duplicados)

Tengo una serie de números que necesito para asegurarme de que son únicos. Encontré el siguiente fragmento de código en Internet y funciona de maravilla hasta que la matriz tiene cero. Encontré este otro script aquí en SO que se ve casi exactamente igual, pero no falla.

Entonces, para ayudarme a aprender, ¿alguien me puede ayudar a determinar dónde está yendo mal el prototipo del guión?

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; } 

Más respuestas de la pregunta duplicada:

  • Eliminar duplicados de la matriz de JavaScript

Pregunta similar:

  • Obtenga todos los valores con más de una ocurrencia (es decir: no única) en una matriz

Con JavaScript 1.6 / ECMAScript 5 puede usar el método de filter nativo de una matriz de la siguiente manera para obtener una matriz con valores únicos:

 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'] 

El filter método nativo recorrerá la matriz y dejará únicamente onlyUnique las entradas que pasen la función de callback dada onlyUnique .

onlyUnique verificaciones onlyUnique , si el valor dado es el primero que ocurre. De lo contrario, debe ser un duplicado y no se copiará.

Esta solución funciona sin ninguna biblioteca adicional como jQuery o prototype.js.

Funciona también para matrices con tipos de valores mixtos.

Para navegadores antiguos (filter e indexOf , puede encontrar soluciones alternativas en la documentación de MDN para filter e indexOf .

Si desea mantener la última aparición de un valor, simplemente reemplace indexOf por lastIndexOf .

Con ES6 podría acortarse a esto:

 // 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'] 

Gracias a Camilo Martin por su sugerencia en el comentario.

ES6 tiene un objeto nativo Set para almacenar valores únicos. Para obtener una matriz con valores únicos, puede hacer ahora esto:

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

El constructor de Set toma un objeto iterable, como Array, y el operador de propagación ... transforma el conjunto de nuevo en una matriz. Gracias a Lukas Liese por un comentario.

Respuesta actualizada para ES6 / ES2015 : con el conjunto , la solución de una sola línea es:

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

Que devuelve

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

Como lo sugirió le_m , esto también se puede acortar usando el operador de propagación , como

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

También puedes usar underscore.js .

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

Me doy cuenta de que esta pregunta ya tiene más de 30 respuestas. Pero he leído primero todas las respuestas existentes e hice mi propia investigación.

Divido todas las respuestas a 4 posibles soluciones:

  1. Use la nueva característica de ES6: [...new Set( [1, 1, 2] )];
  2. Use el objeto { } para evitar duplicados
  3. Usar helper array [ ]
  4. Utilice filter + indexOf

Aquí hay ejemplos de códigos encontrados en las respuestas:

Use la nueva característica de ES6: [...new Set( [1, 1, 2] )];

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

Use el objeto { } para evitar duplicados

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

Usar helper array [ ]

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

Utilice 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; } 

Y me pregunté cuál es más rápido. He hecho hojas de muestra de Google para probar funciones. Nota: ECMA 6 no está disponible en Hojas de cálculo de Google, por lo que no puedo probarlo.

Aquí está el resultado de las pruebas: enter image description here

Esperaba ver que el código que usa el objeto { } ganará porque usa hash. Así que me alegro de que las pruebas hayan arrojado los mejores resultados para este algoritmo en Chrome e IE. Gracias a @rab por el código .

Desde entonces, he encontrado un buen método que utiliza jQuery

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

Nota: Este código fue extraído de la publicación de pato de pato de Paul Irish . Olvidé dar crédito: 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") 

enter image description here

Con syntax de ES5

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

Compatibilidad del navegador : IE9 +

La solución más corta con ES6: [...new Set( [1, 1, 2] )];

O si desea modificar el prototipo de matriz (como en la pregunta original):

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

EcmaScript 6 solo se implementa parcialmente en los navegadores modernos en este momento (agosto de 2015), pero Babel se ha vuelto muy popular para trasladar ES6 (e incluso ES7) a ES5. ¡De esa forma puedes escribir el código ES6 hoy!

Si se pregunta qué significa ... , se llama el operador de propagación . Desde MDN : «El operador de difusión permite que una expresión se expanda en lugares donde se esperan múltiples argumentos (para llamadas a funciones) o múltiples elementos (para literales de matriz)». Como un conjunto es iterable (y solo puede tener valores únicos), el operador de expansión expandirá el conjunto para llenar el conjunto.

Recursos para aprender ES6:

  • Explorando ES6 por el Dr. Axel Rauschmayer
  • Busque “ES6” en los boletines semanales de JS
  • ES6 artículos detallados del blog Mozilla Hacks

La solución más simple:

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

La manera más simple y rápida (en Chrome) de hacer esto:

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

Simplemente revisa cada elemento de la matriz, prueba si ese elemento ya está en la lista, y si no lo está, presiona la matriz que se devuelve.

De acuerdo con jsPerf, esta función es la más rápida de las que pude encontrar en cualquier parte . Sin embargo, puedes agregar la tuya.

La versión no prototipo:

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

Clasificación

Cuando también se necesita ordenar la matriz, la siguiente es la más rápida:

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

o no prototipo:

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

Esto también es más rápido que el método anterior en la mayoría de los navegadores que no son Chrome.

¡DESEMPEÑO SOLAMENTE! este código es probablemente 10 veces más rápido que todos los códigos aquí * funciona en todos los navegadores y también tiene el menor impacto de memoria … y más

si no necesita reutilizar la matriz anterior, por otro lado, realice las otras operaciones necesarias antes de convertirla en única. Probablemente esta sea la forma más rápida de hacerlo, también muy breve.

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

entonces puedes intentar esto

 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] 

Muchas de las respuestas aquí pueden no ser útiles para los principiantes. Si borrar una matriz es difícil, ¿sabrán realmente sobre la cadena del prototipo, o incluso jQuery?

En los navegadores modernos, una solución limpia y simple es almacenar datos en un conjunto , que está diseñado para ser una lista de valores únicos.

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

Array.from es útil para convertir el conjunto de nuevo a una matriz para que tenga acceso fácil a todos los increíbles métodos (características) que tienen las matrices. También hay otras formas de hacer lo mismo. Pero es posible que no necesites Array.from en absoluto, ya que los Sets tienen muchas funciones útiles, como forEach .

Si necesita admitir Internet Explorer antiguo y, por lo tanto, no puede usar Set, entonces una técnica simple es copiar los elementos en una nueva matriz mientras comprueba de antemano si ya están en la nueva matriz.

 // 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); } }); 

Para hacer esto reutilizable instantáneamente, pongámoslo en una función.

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

Entonces, para deshacernos de los duplicados, ahora haríamos esto.

 var uniqueCars = deduplicate(cars); 

La parte deduplicate(cars) convierte en lo que llamamos resultado cuando se completa la función.

Simplemente páselo por el nombre de cualquier matriz que te guste.

Este prototipo getUnique no es del todo correcto, porque si tengo una matriz como: ["1",1,2,3,4,1,"foo"] devolverá ["1","2","3","4"] y "1" es una cadena y 1 es un número entero; ellos son diferentes.

Aquí hay una solución correcta:

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

utilizando:

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

Lo anterior producirá ["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; }, []); 

Sin extender Array.prototype (se dice que es una mala práctica) o usar jquery / underscore, simplemente puede filter la matriz.

Manteniendo la última ocurrencia:

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

o primera aparición:

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

Bueno, solo es JavaScript ECMAScript 5+, lo que significa solo IE9 +, pero es bueno para un desarrollo en HTML / JS nativo (Windows Store App, Firefox OS, Sencha, Phonegap, Titanium, ...).

Eso es porque 0 es un valor falso en JavaScript.

this[i] será falso si el valor de la matriz es 0 o cualquier otro valor falso.

Si está utilizando Prototype Framework no es necesario hacer bucles ‘for’, puede usar http://www.prototypejs.org/api/array/uniq de la siguiente manera:

 var a = Array.uniq(); 

Que producirá una matriz duplicada sin duplicados. Me encontré con tu pregunta buscando un método para contar los distintos registros de la matriz, así que después

uniq ()

solía

tamaño()

y ahí estaba mi simple resultado. ps Lo siento si he malgelado algo

editar: si desea escapar de registros no definidos, es posible que desee agregar

compacto()

antes, así:

 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 } 

No estoy seguro de por qué Gabriel Silveira escribió la función de esa manera, pero una forma más simple que me funciona igual de bien y sin la minificación es:

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

o en CoffeeScript:

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

con es6 (y mantiene el orden):

 [...new Set(myArray)]; 

Haga un conjunto de la matriz y luego inicialice una copia superficial del conjunto en el contenedor deseado.

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

Del blog de Shamasis Bhattacharya (O (2n) complejidad del tiempo):

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

Del blog de Paul Irish : mejora en 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] 

Encontrar valores únicos de Array en método simple

 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] 

Para solucionar el problema al revés, puede ser útil no tener duplicados mientras carga su matriz, como lo haría Set object pero aún no está disponible en todos los navegadores. Ahorra memoria y es más eficiente si necesita ver su contenido muchas veces.

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

Muestra:

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

Te da set = [1,3,4,2]

Es extraño que esto no se haya sugerido antes … para eliminar duplicados por clave de objeto ( id continuación) en una matriz, puedes hacer algo como esto:

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

Hay una manera fácil de resolver esta tarea a través de ES6 – usando Set:

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

También puedes usar 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] 

Originalmente respondido en: jQuery función para obtener todos los elementos únicos de una matriz?

Si alguien usa knockoutjs

 ko.utils.arrayGetDistinctValues() 

Por cierto, mira todas las utilidades ko.utils.array* .

Descubrí que serializar la clave hash me ayudó a hacer que esto funcione para los objetos.

 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; } 

También puedes usar 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"}] 

Podemos hacer esto usando conjuntos de ES6:

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

// La salida será

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