Pregunta 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:

Pregunta similar:


779
2017-12-25 04:28


origen


Respuestas:


Con JavaScript 1.6 / ECMAScript 5 puedes usar el nativo filter método 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 método nativo filter recorrerá la matriz y dejará solo aquellas entradas que pasen la función de devolución de llamada dada onlyUnique.

onlyUnique cheques, 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 (<ie9), que no admiten los métodos nativos filter y indexOf puede encontrar soluciones alternativas en la documentación de MDN para filtrar y índice de.

Si desea mantener la última ocurrencia de un valor, reemplace simple 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 para insinuar 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 para insinuar en el comentario.


1465
2018-01-21 12:46



Respuesta actualizada para ES6 / ES2015: Utilizando 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 le_m sugerido, esto también se puede acortar usando operador de propagación , me gusta

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

488
2017-10-14 09:42



También puedes usar underscore.js.

console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>

que regresará:

[1, 2, 3, 4]

116
2017-07-11 16:25



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. Usar el objeto { } para evitar duplicados
  3. Utilice la matriz de ayuda [ ]
  4. Utilizar 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    
}

Usar 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];
  });
} 

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

Utilizar 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 muestra la hoja 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 ese código usando un 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.


87
2018-03-27 12:24



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 Paul Irish's duck punching - Olvidé dar crédito: P


51
2017-07-12 15:41



One Liner, Pure JavaScript

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")

enter image description here

Con sintaxis de ES5

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

Compatibilidad del navegador: IE9 +


44
2017-09-01 13:32



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 es solo parcialmente implementado en los navegadores modernos en este momento (agosto de 2015), pero Babel se ha vuelto muy popular para transpilar ES6 (e incluso ES7) de vuelta a ES5. ¡De esa forma puedes escribir el código ES6 hoy!

Si te preguntas qué ... significa que se llama operador de propagación. De 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:


39
2018-04-23 12:42



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


31
2018-03-14 22:01



El más simple, y lo más rápido (en Chrome) forma 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, 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 el más rápido de los que pude encontrar en cualquier lugar - No dude en agregar su propio pensamiento.

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, la siguiente es la más rápida:

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 es también más rápido que el método anterior en la mayoría de los navegadores que no son Chrome.


30
2018-01-30 00:10



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

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 while-- loop. mientras que es el bucle más rápido en todos los navegadores excepto el que a todos nos gusta tanto ... 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()

El próximo paso usa js moderno.Object.keys reemplacé el otro por bucle con Object.keys de js1.7 ... un poco más rápido y más corto (en cromo 2 veces más rápido);). ¡No es suficiente!.unique3().

en este momento estaba pensando en lo que realmente necesito en MI función única. No necesito la matriz anterior, quiero una función rápida. así que usé 2 mientras bucles + empalme.unique4()

Inútil decir que estaba impresionado.

cromo: las usuales 150,000 operaciones por segundo aumentaron a 1,800,000 operaciones por segundo.

es decir: 80,000 op / s versus 3,500,000 op / s

ios: 18,000 op / s versus 170,000 op / s

safari: 80,000 op / s versus 6,000,000 op / s

Prueba http://jsperf.com/wgu o mejor use console.time ... microtime ... whatever

unique5() es solo para mostrarte lo que sucede si quieres mantener la matriz anterior.

No usar Array.prototype si no sabes lo que estás haciendo. acabo de hacer una gran cantidad de copias y pasadas. Utilizar Object.defineProperty(Array.prototype,...,writable:false,enumerable:false}) si quieres crear un prototipo nativo. Ejemplo: https://stackoverflow.com/a/20463021/2450730

Manifestación http://jsfiddle.net/46S7g/

NOTA: su matriz anterior se destruye / convierte en única después de esta operación.

si no puede leer el código anterior pregunte, lea un libro de JavaScript o aquí hay algunas explicaciones sobre el código más corto. https://stackoverflow.com/a/21353032/2450730

algunos están usando indexOf  ... no ... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh

para matrices vacías

!array.length||toUnique(array); 

29
2017-08-01 14:49