En Javascript, ¿cómo verifico si una matriz tiene valores duplicados?

95

Posible duplicado:
forma más fácil de encontrar valores duplicados en una matriz de JavaScript

¿Cómo verifico si una matriz tiene valores duplicados?

Si algunos elementos de la matriz son iguales, devuelve verdadero. De lo contrario, devuelve falso.

['hello','goodbye','hey'] //return false because no duplicates exist
['hello','goodbye','hello'] // return true because duplicates exist

Tenga en cuenta que no me importa encontrar la duplicación, solo quiero un resultado booleano si las matrices contienen duplicaciones.

usuario847495
fuente
Aquí está: stackoverflow.com/questions/840781/…
Ofer Zelig
2
No quiero que se elimine una lista de duplicados. Solo quiero saber verdadero o falso si una lista tiene duplicados.
user847495
7
Esta pregunta no es un duplicado. Dado que @ user847495 simplemente quiere verificar si existen duplicados, la solución es más rápida / fácil de lo que se necesita para encontrar todas las apariciones de duplicados. Por ejemplo, puede hacer esto: codr.io/v/bvzxhqm
alden
2
usando subrayado , técnica simplevar test=['hello','goodbye','hello'] ; if ( test.length != _.unique(test).length ) { // some code }
Sai Ram
4
No es un duplicado de la pregunta marcada. Preste atención antes de marcar las preguntas como tales.
John Weisz

Respuestas:

222

Si tiene un entorno ES2015 (al momento de escribir este artículo: io.js, IE11, Chrome, Firefox, WebKit nightly), lo siguiente funcionará y será rápido (a saber, O (n)):

function hasDuplicates(array) {
    return (new Set(array)).size !== array.length;
}

Si solo necesita valores de cadena en la matriz, lo siguiente funcionará:

function hasDuplicates(array) {
    var valuesSoFar = Object.create(null);
    for (var i = 0; i < array.length; ++i) {
        var value = array[i];
        if (value in valuesSoFar) {
            return true;
        }
        valuesSoFar[value] = true;
    }
    return false;
}

Usamos una "tabla hash" valuesSoFarcuyas claves son los valores que hemos visto en la matriz hasta ahora. Hacemos una búsqueda usando inpara ver si ese valor ya ha sido detectado; si es así, salimos del bucle y regresamos true.


Si necesita una función que funcione para algo más que valores de cadena, lo siguiente funcionará, pero no es tan eficaz; es O (n 2 ) en lugar de O (n).

function hasDuplicates(array) {
    var valuesSoFar = [];
    for (var i = 0; i < array.length; ++i) {
        var value = array[i];
        if (valuesSoFar.indexOf(value) !== -1) {
            return true;
        }
        valuesSoFar.push(value);
    }
    return false;
}

La diferencia es simplemente que usamos una matriz en lugar de una tabla hash valuesSoFar, ya que las "tablas hash" de JavaScript (es decir, los objetos) solo tienen claves de cadena. Esto significa que perdemos el tiempo de búsqueda O (1) de in, en lugar de obtener un tiempo de búsqueda O (n) de indexOf.

Domenic
fuente
3
Sobre el primer ejemplo que diste. ¿No es la validación exactamente al revés? Si se nombra su función hasDuplicates, entonces debería verificar si el tamaño del conjunto realmente se redujo durante el proceso de conversión, ¿verdad? Por lo tanto, el operador booleano debería ser !==y no===
Tim Daubenschütz
por favor editar. No puedo editar porque no cambio más de 6 caracteres.
Tim Daubenschütz
1
Según MDN, IE11 no es compatible con el constructor utilizado en el primer ejemplo
adam77
La versión normal de JS regresa truepara la siguiente matriz:[1, '1']
Kunal
Por lo tanto, "si solo necesita valores de cadena en la matriz" antes de la respuesta.
Domenic
4

Otro enfoque (también para elementos de objeto / matriz dentro de la matriz 1 ) podría ser 2 :

function chkDuplicates(arr,justCheck){
  var len = arr.length, tmp = {}, arrtmp = arr.slice(), dupes = [];
  arrtmp.sort();
  while(len--){
   var val = arrtmp[len];
   if (/nul|nan|infini/i.test(String(val))){
     val = String(val);
    }
    if (tmp[JSON.stringify(val)]){
       if (justCheck) {return true;}
       dupes.push(val);
    }
    tmp[JSON.stringify(val)] = true;
  }
  return justCheck ? false : dupes.length ? dupes : null;
}
//usages
chkDuplicates([1,2,3,4,5],true);                           //=> false
chkDuplicates([1,2,3,4,5,9,10,5,1,2],true);                //=> true
chkDuplicates([{a:1,b:2},1,2,3,4,{a:1,b:2},[1,2,3]],true); //=> true
chkDuplicates([null,1,2,3,4,{a:1,b:2},NaN],true);          //=> false
chkDuplicates([1,2,3,4,5,1,2]);                            //=> [1,2]
chkDuplicates([1,2,3,4,5]);                                //=> null

Ver también...

1 necesita un navegador que admita JSON, o una biblioteca JSON si no.
2 edición: la función ahora se puede usar para una verificación simple o para devolver una matriz de valores duplicados

KooiInc
fuente
3
Problemas no sorprendentes que vale la pena tener en cuenta: 1) muta la matriz original para ser ordenada; 2) no diferencia entre null, NaN, Infinity, +Infinity, y -Infinity; 3) los objetos se consideran iguales si tienen las mismas propiedades propias, incluso si tienen diferentes prototipos.
Domenic
1
@Domenic: sí, debería haberlo mencionado. Editado para evitar la mutación de la matriz original.
KooiInc
@Domenic: corregido para nulo / NaN / [+/-] Infinito, ver ediciones.
KooiInc
@Domenic: Número 3) en realidad no es un problema para mí, porque es exactamente lo que quiero. No me importa el prototipo, solo los valores.
asombro el