Em Javascript, como faço para verificar se uma matriz tem valores duplicados?

98

Possível duplicata:
maneira mais fácil de encontrar valores duplicados em uma matriz javascript

Como posso verificar se uma matriz tem valores duplicados?

Se alguns elementos da matriz forem iguais, retorne verdadeiro. Caso contrário, retorna falso.

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

Observe que não me importo em encontrar a duplicação, só quero o resultado booleano se os arrays contiverem duplicações.

user847495
fonte
2
Eu não quero uma lista de duplicatas removida. Eu só quero saber verdadeiro ou falso se uma lista contém duplicatas.
user847495
7
Esta pergunta não é uma duplicata. Como @ user847495 deseja apenas verificar se existem duplicatas, a solução é mais rápida / fácil do que o necessário para localizar todas as ocorrências de duplicatas. Por exemplo, você pode fazer isso: codr.io/v/bvzxhqm
alden
2
usando sublinhado , técnica simplesvar test=['hello','goodbye','hello'] ; if ( test.length != _.unique(test).length ) { // some code }
Sai Ram
4
Não é uma duplicata da pergunta marcada. Preste atenção antes de marcar perguntas como tais.
John Weisz

Respostas:

228

Se você tiver um ambiente ES2015 (no momento da redação deste artigo: io.js, IE11, Chrome, Firefox, WebKit noturno), o seguinte funcionará e será rápido (viz. O (n)):

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

Se você só precisa de valores de string na matriz, o seguinte 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 uma "tabela de hash" valuesSoFarcujas chaves são os valores que vimos no array até agora. Fazemos uma pesquisa usando inpara ver se esse valor já foi localizado; se for assim, saímos do circuito e voltamos true.


Se você precisa de uma função que funcione para mais do que apenas valores de string, o seguinte funcionará, mas não tem um desempenho tão bom; é O (n 2 ) em vez 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;
}

A diferença é simplesmente que usamos um array em vez de uma tabela hash para valuesSoFar, uma vez que as "tabelas hash" JavaScript (ou seja, objetos) têm apenas chaves de string. Isso significa que perdemos o tempo de pesquisa O (1) de in, em vez de obter um tempo de pesquisa O (n) de indexOf.

Domenic
fonte
3
Sobre o primeiro exemplo que você deu. A validação não é exatamente o contrário? Se sua função for nomeada hasDuplicates, ela deve verificar se o tamanho do conjunto realmente encolheu durante o processo de conversão, certo? Portanto, o operador booleano deve ser !==e não===
Tim Daubenschütz
pls edit. Não posso editar porque não estou alterando mais de 6 caracteres.
Tim Daubenschütz
1
De acordo com MDN, o IE11 não suporta o construtor usado no primeiro exemplo
adam77 01 de
1
A versão JS normal retorna truepara a seguinte matriz:[1, '1']
Kunal
Portanto, "se você só precisar de valores de string na matriz" antes da resposta.
Domenic de
5

Outra abordagem (também para elementos de objeto / matriz dentro da matriz 1 ) poderia 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

Veja também...

1 precisa de um navegador que suporte JSON ou uma biblioteca JSON se não for.
2 editar: a função agora pode ser usada para verificação simples ou para retornar uma matriz de valores duplicados

KooiInc
fonte
3
Questões que não impedem a exibição que valem a pena estar atentas: 1) altera o array original a ser classificado; 2) não diferenciam entre null, NaN, Infinity, +Infinity, e -Infinity; 3) os objetos são considerados iguais se tiverem as mesmas propriedades próprias, mesmo que tenham protótipos diferentes.
Domenic,
1
@Domenic: sim, deveria ter mencionado isso. Editado para contornar a mutação da matriz original.
KooiInc
@Domenic: corrigido para null / NaN / [+/-] Infinity, consulte as edições.
KooiInc
@Domenic: A questão 3) não é realmente um problema para mim, porque é exatamente o que eu quero. Não me importo com o protótipo, apenas com os valores.
maravilhada de