repetidos - Obtenga todos los valores únicos en una matriz de JavaScript(eliminar duplicados)
filter javascript (30)
One Liner, JavaScript puro
Con sintaxis 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")
Con la sintaxis de ES5
list = list.filter(function (x, i, a) {
return a.indexOf(x) == i;
});
Compatibilidad del navegador : IE9 +
Tengo una serie de números que necesito para asegurarme de que son únicos. Encontré el fragmento de código a continuación en Internet y funciona muy bien hasta que la matriz tenga un cero. Encontré este otro script aquí en SO que se ve casi exactamente igual, pero no falla.
Entonces, por el simple hecho de ayudarme a aprender, ¿puede alguien ayudarme a determinar dónde va mal el guión del prototipo?
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:
Pregunta similar:
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 solo dejará aquellas entradas que pasan la onlyUnique
función de devolución de llamada onlyUnique
.
onlyUnique
comprueba, si el valor dado es el primero que ocurre. Si no, debe ser un duplicado y no se copiará.
Esta solución funciona sin ninguna biblioteca adicional como jQuery o prototype.js.
Funciona para arreglos con tipos de valores mixtos también.
Para los navegadores antiguos (<ie9), que no son compatibles con los métodos de filter
e indexOf
, puede encontrar soluciones 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 se podría reducir 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 sugerencia en el comentario.
ES6 tiene un objeto nativo Set
para almacenar valores únicos. Para obtener una matriz con valores únicos, ahora puedes hacer 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 set de nuevo en un Array. Gracias a Lukas Liese por sugerencia en el comentario.
Del http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/ (O (2n) complejidad de tiempo):
Array.prototype.unique = function() {
var o = {}, i, l = this.length, r = [];
for(i=0; i<l;i+=1) o[this[i]] = this[i];
for(i in o) r.push(o[i]);
return r;
};
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]
Descubrí que serializar la clave hash me ayudó a hacer que esto funcionara 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;
}
Desde entonces he encontrado un buen método que usa jQuery
arr = $.grep(arr, function(v, k){
return $.inArray(v ,arr) === k;
});
Nota: este código se extrajo del puesto de perforación de pato de Paul Irish . Olvidé dar crédito: P
Encontrar valores de Array únicos en un 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]
Eso es porque 0
es un valor falso en JavaScript.
this[i]
será falsy si el valor de la matriz es 0 o cualquier otro valor falsy.
Este prototipo getUnique
no es totalmente 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"]
.
Esto funcionará.
function getUnique(a) {
var b = [a[0]], i, j, tmp;
for (i = 1; i < a.length; i++) {
tmp = 1;
for (j = 0; j < b.length; j++) {
if (a[i] == b[j]) {
tmp = 0;
break;
}
}
if (tmp) {
b.push(a[i]);
}
}
return b;
}
La forma más simple y fastest (en Chrome) de hacer esto:
Array.prototype.unique = function() {
var a = [];
for (var i=0, l=this.length; i<l; i++)
if (a.indexOf(this[i]) === -1)
a.push(this[i]);
return a;
}
Simplemente revisa cada elemento de la matriz, comprueba si ese elemento ya está en la lista y, si no lo está, presione la matriz que se devuelve.
De acuerdo con jsPerf, esta función es fastest , siéntete libre de agregar la tuya.
La versión no prototipo:
function uniques(arr) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
if (a.indexOf(arr[i]) === -1 && arr[i] !== '''')
a.push(arr[i]);
return a;
}
Clasificación
Cuando también se necesita ordenar la matriz, lo más rápido es lo siguiente:
Array.prototype.sortUnique = function() {
this.sort();
var last_i;
for (var i=0;i<this.length;i++)
if ((last_i = this.lastIndexOf(this[i])) !== i)
this.splice(i+1, last_i-i);
return this;
}
o no prototipo:
function sortUnique(arr) {
arr.sort();
var last_i;
for (var i=0;i<arr.length;i++)
if ((last_i = arr.lastIndexOf(arr[i])) !== i)
arr.splice(i+1, last_i-i);
return arr;
}
Esto también es fastest en la mayoría de los navegadores que no son de Chrome.
La solución más corta con ES6: [...new Set( [1, 1, 2] )];
O si desea modificar el prototipo de Array (como en la pregunta original):
Array.prototype.getUnique = function() {
return [...new Set( [this] )];
};
EcmaScript 6 solo está parcialmente implementado en los navegadores modernos en este momento (agosto de 2015), pero Babel ha vuelto muy popular para transpilar ES6 (e incluso ES7) de vuelta a ES5. De esa manera puedes escribir código ES6 hoy!
Si te estás preguntando qué significa ...
, se llama 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 de función) o múltiples elementos (para literales de matriz)». Debido a que un Conjunto es iterable (y solo puede tener valores únicos), el operador de propagación expandirá el Conjunto para llenar la matriz.
Recursos para aprender ES6:
- Explorando ES6 por el Dr. Axel Rauschmayer
- Busque “ES6” en los boletines semanales de JS
- ES6 en profundidad artículos 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)]);
O:
var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log(Array.from(new Set(arr)));
Me doy cuenta de que esta pregunta ya tiene más de 30 respuestas. Pero primero he leído todas las respuestas existentes y he hecho mi propia investigación.
Dividí todas las respuestas a 4 soluciones posibles:
- Utilice la nueva función ES6:
[...new Set( [1, 1, 2] )];
- Usa el objeto
{ }
para evitar duplicados - Utilizar matriz de ayuda
[ ]
- Usa
filter + indexOf
Aquí hay ejemplos de códigos encontrados en las respuestas:
Utilice la nueva función ES6: [...new Set( [1, 1, 2] )];
function uniqueArray0(array) {
var result = Array.from(new Set(array));
return result
}
Usa 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];
});
}
Utilizar matriz de ayuda [ ]
function uniqueArray2(arr) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
if (a.indexOf(arr[i]) === -1 && arr[i] !== '''')
a.push(arr[i]);
return a;
}
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;
}
Y me pregunté cuál es más rápido. He hecho una muestra de Google Sheet para probar funciones. Nota: ECMA 6 no está disponible en Google Sheets, así que no puedo probarlo.
Aquí está el resultado de las pruebas:
Esperaba ver que el código que usa el objeto { }
gane porque usa hash. Así que me alegro de que las pruebas hayan mostrado los mejores resultados para este algoritmo en Chrome e IE. Gracias a @rab por el código .
Muchas de las respuestas aquí pueden no ser útiles para los principiantes. Si es difícil desentregar una matriz, ¿conocerán realmente la cadena del prototipo o incluso jQuery?
En los navegadores modernos, una solución limpia y simple es almacenar datos en un Set , 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));
El Array.from
es útil para volver a convertir el Conjunto en un Array para que tenga fácil acceso a todos los métodos (características) impresionantes que tienen los arrays. También hay otras formas de hacer lo mismo. Pero es posible que no necesite Array.from
en absoluto, ya que los Conjuntos tienen muchas características útiles como forEach .
Si necesita admitir el antiguo Internet Explorer y, por lo tanto, no puede usar Set, entonces una técnica simple es copiar elementos en una nueva matriz mientras comprueba de antemano si ya están en la nueva.
// 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
// - a.k.a. 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 hacerlo reutilizable al instante, 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;
}
}
Así que para deshacernos de los duplicados, ahora haríamos esto.
var uniqueCars = deduplicate(cars);
La parte deduplicate(cars)
convierte en lo que llamamos resultado cuando la función se completa.
Simplemente pásale el nombre de cualquier matriz que te guste.
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
)
Para solucionar el problema al revés, puede ser útil no tener duplicados mientras carga su matriz, la forma en que Set object lo haría, pero aún no está disponible en todos los navegadores. Ahorra memoria y es más eficiente si necesita mirar 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]
Podemos hacer esto usando sets 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];
Si alguien usa knockoutjs
ko.utils.arrayGetDistinctValues()
Por cierto, eche un vistazo a todas las utilidades ko.utils.array*
.
Si está utilizando Prototype Framework, no hay necesidad de hacer bucles ''for'', puede usar http://www.prototypejs.org/api/array/uniq así:
var a = Array.uniq();
Lo que producirá una matriz duplicada sin duplicados. Me encontré con su pregunta buscando un método para contar distintos registros de matriz, así que después de
uniq ()
solía
tamaño()
Y ahí estaba mi simple resultado. ps disculpa si escribí mal algo
edición: si desea escapar de registros no definidos, puede agregar
compacto()
antes, así:
var a = Array.compact().uniq();
Sin extender el Array.prototype (se dice que es una mala práctica) o usar jquery / guión bajo, 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 ocurrencia:
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, ...).
También puede utilizar underscore.js .
console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>
que volverá:
[1, 2, 3, 4]
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"}]
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 respondida en: jQuery function para obtener todos los elementos únicos de una matriz?
extraño, esto no se ha sugerido antes ... para eliminar duplicados por clave de objeto ( id
abajo) en una matriz, puede hacer algo como esto:
const uniqArray = array.filter((obj, idx, arr) => (
arr.findIndex((o) => o.id === obj.id) === idx
))
Respuesta actualizada para ES6 / ES2015 : usando el Set , 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 le_m sugirió, esto también puede acortarse usando un operador de propagación , como
var uniqueItems = [...new Set(items)]
SÓLO FUNCIONAMIENTO! 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 cierto, realizar las otras operaciones necesarias antes de convertirla en exclusiva aquí es probablemente 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 probar 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]
Se me ocurrió esta función leyendo este artículo ...
http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/
No me gusta el bucle for. Tiene muchos parámetros. Me gusta el bucle while. while es el bucle más rápido en todos los navegadores excepto en el que a todos nos gusta mucho ... Chrome.
de todos modos escribí la primera función que usa while. Y sí, es un poco más rápido que la función que se encuentra en el artículo. Pero no es suficiente. unique2()
siguiente paso usa js modernos. Object.keys
reemplazado el otro para loop con Object.keys de js1.7 ... un poco más rápido y más corto (en Chrome 2x más rápido);). ¡No es suficiente!. unique3()
.
en este punto, estaba pensando en lo que realmente necesito en MI función única. No necesito la matriz antigua, quiero una función rápida. así que usé 2 mientras bucles + empalme. unique4()
Inútil decir que me quedé impresionado.
Chrome: las 150,000 operaciones habituales por segundo saltaron a 1,800,000 operaciones por segundo.
es decir: 80,000 op / s contra 3,500,000 op / s
ios: 18,000 op / s vs 170,000 op / s
safari: 80,000 op / s vs 6,000,000 op / s
Probar http://jsperf.com/wgu o mejor use console.time ... microtime ... lo que sea
unique5()
es solo para mostrarle lo que sucede si desea mantener la matriz anterior.
No use Array.prototype
si no sabe lo que está haciendo. Acabo de hacer un montón de copia y pasado. Utilice Object.defineProperty(Array.prototype,...,writable:false,enumerable:false})
si desea crear un prototype.example nativo: https://.com/a/20463021/2450730
Demostración http://jsfiddle.net/46S7g/
NOTA: su antigua matriz se destruye / se vuelve a unir después de esta operación.
Si no puedes leer el código anterior, pregunta, lee un libro de JavaScript o aquí hay algunas explicaciones sobre el código más corto. https://.com/a/21353032/2450730
algunos están usando indexOf
... no ... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh
para matrices vacias
!array.length||toUnique(array);
Sobre la base de otras respuestas, aquí hay otra variante que toma una marca opcional para elegir una estrategia (mantener la primera aparición o la última):
Sin extender Array.prototype
function unique(arr, keepLast) {
return arr.filter(function (value, index, array) {
return keepLast ? array.indexOf(value, index + 1) < 0 : array.indexOf(value) === index;
});
};
// Usage
unique([''a'', 1, 2, ''1'', 1, 3, 2, 6]); // -> [''a'', 1, 2, ''1'', 3, 6]
unique([''a'', 1, 2, ''1'', 1, 3, 2, 6], true); // -> [''a'', ''1'', 1, 3, 2, 6]
Extensible Array.prototype
Array.prototype.unique = function (keepLast) {
return this.filter(function (value, index, array) {
return keepLast ? array.indexOf(value, index + 1) < 0 : array.indexOf(value) === index;
});
};
// Usage
[''a'', 1, 2, ''1'', 1, 3, 2, 6].unique(); // -> [''a'', 1, 2, ''1'', 3, 6]
[''a'', 1, 2, ''1'', 1, 3, 2, 6].unique(true); // -> [''a'', ''1'', 1, 3, 2, 6]
Usando claves de objeto para hacer una matriz única, he intentado seguir
function uniqueArray( ar ) {
var j = {};
ar.forEach( function(v) {
j[v+ ''::'' + typeof v] = v;
});
return Object.keys(j).map(function(v){
return j[v];
});
}
uniqueArray(["1",1,2,3,4,1,"foo", false, false, null,1]);
Que devuelve ["1", 1, 2, 3, 4, "foo", false, null]
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
}
["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;
}, []);