Obter todos os valores não exclusivos (isto é: duplicado / mais de uma ocorrência) em uma matriz

Eu preciso verificar um array JavaScript para ver se há algum valor duplicado. Qual é a maneira mais fácil de fazer isso? Eu só preciso encontrar o que os valores duplicados são – eu realmente não preciso de seus índices ou quantas vezes eles são duplicados.

Eu sei que posso percorrer a matriz e verificar todos os outros valores para uma correspondência, mas parece que deve haver uma maneira mais fácil. Alguma ideia? Obrigado!

Pergunta semelhante:

  • Obter todos os valores exclusivos em uma matriz (remover duplicatas)

Você poderia classificar a matriz e, em seguida, percorrê-la e, em seguida, ver se o próximo índice (ou anterior) é o mesmo que o atual. Assumindo que seu algoritmo de ordenação é bom, isso deve ser menor que O (n 2 ):

var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7]; var sorted_arr = arr.slice().sort(); // You can define the comparing function here. // JS by default uses a crappy string compare. // (we use slice to clone the array so the // original array won't be modified) var results = []; for (var i = 0; i < sorted_arr.length - 1; i++) { if (sorted_arr[i + 1] == sorted_arr[i]) { results.push(sorted_arr[i]); } } console.log(results); 

Se você deseja eliminar as duplicatas, tente esta ótima solução:

 function eliminateDuplicates(arr) { var i, len = arr.length, out = [], obj = {}; for (i = 0; i < len; i++) { obj[arr[i]] = 0; } for (i in obj) { out.push(i); } return out; } 

Fonte: http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/

Esta é a minha resposta do tópico duplicado (!):

Cansei de ver todos os exemplos ruins com for-loops ou jQuery. Javascript tem as ferramentas perfeitas para isso hoje em dia: classificar, mapear e reduzir.

Encontre itens duplicados

 var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'] var uniq = names .map((name) => { return {count: 1, name: name} }) .reduce((a, b) => { a[b.name] = (a[b.name] || 0) + b.count return a }, {}) var duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1) console.log(duplicates) // [ 'Nancy' ] 

Sintaxe mais funcional:

@ Dmytro-Laptin apontou algum código de código a ser removido. Esta é uma versão mais compacta do mesmo código. Usando alguns truques ES6 e funções de ordem superior:

 const names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'] const count = names => names.reduce((a, b) => Object.assign(a, {[b]: (a[b] || 0) + 1}), {}) const duplicates = dict => Object.keys(dict).filter((a) => dict[a] > 1) console.log(count(names)) // { Mike: 1, Matt: 1, Nancy: 2, Adam: 1, Jenny: 1, Carl: 1 } console.log(duplicates(count(names))) // [ 'Nancy' ] 

Usando o Function.prototype.bind:

  // prep const arr = Array.from('Learn more javascript dude'); const counter = (prev, next) => Object.assign(prev, { [next] : (prev[next] || 0) + 1 }); const singles = function(key){ return this[key] === 1 }; const multiples = function(key){ return this[key] > 1 }; // work const counted = arr.reduce(counter, {}); const filtered = Object.keys(counted).filter(multiples.bind(counted)); //[ "e", "a", "r", " ", "d" ] console.log(filtered); 

Você pode adicionar esta function, ou ajustá-lo e adicioná-lo ao protótipo Array do Javascript:

 Array.prototype.unique = function () { var r = new Array(); o:for(var i = 0, n = this.length; i < n; i++) { for(var x = 0, y = r.length; x < y; x++) { if(r[x]==this[i]) { alert('this is a DUPE!'); continue o; } } r[r.length] = this[i]; } return r; } var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,9]; var unique = arr.unique(); alert(unique); 

ATUALIZADO: O seguinte usa uma estratégia combinada otimizada. Ele otimiza as pesquisas primitivas para se beneficiar do tempo de pesquisa do hash O (1) (a execução unique em uma matriz de primitivas é O (n)). As pesquisas de object são otimizadas por meio da marcação de objects com um ID exclusivo, enquanto iterar por meio da identificação de objects duplicados também é O (1) por item e O (n) para toda a lista. A única exceção são itens que são congelados, mas são raros e um fallback é fornecido usando uma matriz e indexOf.

 var unique = function(){ var hasOwn = {}.hasOwnProperty, toString = {}.toString, uids = {}; function uid(){ var key = Math.random().toString(36).slice(2); return key in uids ? uid() : uids[key] = key; } function unique(array){ var strings = {}, numbers = {}, others = {}, tagged = [], failed = [], count = 0, i = array.length, item, type; var id = uid(); while (i--) { item = array[i]; type = typeof item; if (item == null || type !== 'object' && type !== 'function') { // primitive switch (type) { case 'string': strings[item] = true; break; case 'number': numbers[item] = true; break; default: others[item] = item; break; } } else { // object if (!hasOwn.call(item, id)) { try { item[id] = true; tagged[count++] = item; } catch (e){ if (failed.indexOf(item) === -1) failed[failed.length] = item; } } } } // remove the tags while (count--) delete tagged[count][id]; tagged = tagged.concat(failed); count = tagged.length; // append primitives to results for (i in strings) if (hasOwn.call(strings, i)) tagged[count++] = i; for (i in numbers) if (hasOwn.call(numbers, i)) tagged[count++] = +i; for (i in others) if (hasOwn.call(others, i)) tagged[count++] = others[i]; return tagged; } return unique; }(); 

Se você tem collections ES6 disponíveis, então há uma versão muito mais simples e significativamente mais rápida. (shim para o IE9 + e outros navegadores aqui: https://github.com/Benvie/ES6-Harmony-Collections-Shim )

 function unique(array){ var seen = new Set; return array.filter(function(item){ if (!seen.has(item)) { seen.add(item); return true; } }); } 

Encontre valores duplicados em uma matriz

Essa deve ser uma das maneiras mais curtas de encontrar valores duplicados em uma matriz. Conforme solicitado especificamente pelo OP, isso não remove duplicatas, mas as encontra .

 var input = [1, 2, 3, 1, 3, 1]; var duplicates = input.reduce(function(acc, el, i, arr) { if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc; }, []); document.write(duplicates); // = 1,3 (actual array == [1, 3]) 

Isso deve te dar o que você quer, apenas as duplicatas.

 function find_duplicates(arr) { var len=arr.length, out=[], counts={}; for (var i=0;i= 1 ? counts[item] + 1 : 1; if (counts[item] === 2) { out.push(item); } } return out; } find_duplicates(['one',2,3,4,4,4,5,6,7,7,7,'pig','one']); // -> ['one',4,7] in no particular order. 

usando underscore.js

 function hasDuplicate(arr){ return (arr.length != _.uniq(arr).length); } 
 var a = ["a","a","b","c","c"]; a.filter(function(value,index,self){ return (self.indexOf(value) !== index )}) 
 var a = [324,3,32,5,52,2100,1,20,2,3,3,2,2,2,1,1,1].sort(); a.filter(function(v,i,o){return i&&v!==o[i-1]?v:0;}); 

ou quando adicionado ao protótipo.chain da matriz

 //copy and paste: without error handling Array.prototype.unique = function(){return this.sort().filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});} 

Veja aqui: https://gist.github.com/1305056

Quando tudo o que você precisa é verificar que não há duplicatas, conforme solicitado nesta pergunta, você pode usar o método every() :

 [1, 2, 3].every(function(elem, i, array){return array.lastIndexOf(elem) === i}) // true [1, 2, 1].every(function(elem, i, array){return array.lastIndexOf(elem) === i}) // false 

Note que every() não funciona para o IE 8 e abaixo.

Eu uso lastIndexOf() porque pode ser mais eficiente que indexOf() se os retornos de chamada de function feitos por every() forem feitos na ordem de índice, mas isso não está provado.

No CoffeeScript estou usando isso:

 Array::duplicates = -> not @every((elem, i, array) -> array.lastIndexOf(elem) is i) [1, 2, 3].duplicates() // false [1, 2, 1].duplicates() // true 

Encontre valores exclusivos de 3 matrizes (ou mais):

 Array.prototype.unique = function () { var arr = this.sort(), i; // input must be sorted for this to work for( i=arr.length; i--; ) arr[i] === arr[i-1] && arr.splice(i,1); // remove duplicate item return arr; } var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,9], arr2 = [1,2,511,12,50], arr3 = [22], unique = arr.concat(arr2, arr3).unique(); console.log(unique); // [22, 50, 12, 511, 2, 1, 9, 5, 8, 7, 3, 6, 4] 

Apenas um polyfill para matriz IndexOf para navegadores antigos:

 if (!Array.prototype.indexOf){ Array.prototype.indexOf = function(elt /*, from*/){ var len = this.length >>> 0; var from = Number(arguments[1]) || 0; from = (from < 0) ? Math.ceil(from) : Math.floor(from); if (from < 0) from += len; for (; from < len; from++){ if (from in this && this[from] === elt) return from; } return -1; }; } 

Solução de jQuery usando "inArray":

 if( $.inArray(this[i], arr) == -1 ) 

ES2015

 var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,22], arr2 = [1,2,511,12,50], arr3 = [22], unique; // Combine all the arrays to a single one unique = arr.concat(arr2, arr3); // create a new (dirty) Array with only the unique items unique = unique.map((item,i) => unique.includes(item, i+1) ? item : '' ) // Cleanup - remove duplicate & empty items items unique = [...new Set(unique)].filter(n => n); console.log(unique); 

Código simples com syntax ES6 (matriz ordenada de retorno de duplicados):

 let duplicates = a => {d=[]; a.sort((a,b) => ab).reduce((a,b)=>{a==b&&!d.includes(a)&&d.push(a); return b}); return d}; 

Como usar:

 duplicates([1,2,3,10,10,2,3,3,10]); 

A seguinte function (uma variação da function eliminarDuplicados já mencionada) parece fazer o truque, retornando o teste2,1,7,5 para a input [“teste”, “teste2”, “teste2”, 1, 1, 1, 2 3, 4, 5, 6, 7, 7, 10, 22, 43, 1, 5, 8]

Observe que o problema é mais estranho em JavaScript do que na maioria das outras linguagens, porque uma matriz JavaScript pode conter praticamente qualquer coisa. Observe que as soluções que usam sorting podem precisar fornecer uma function de sorting apropriada – ainda não experimentei essa rota.

Essa implementação específica funciona para (pelo menos) seqüências e números.

 function findDuplicates(arr) { var i, len=arr.length, out=[], obj={}; for (i=0;i 

Aqui está uma maneira muito leve e fácil:

 var codes = dc_1.split(','); var i = codes.length; while (i--) { if (codes.indexOf(codes[i]) != i) { codes.splice(i,1); } } 
 var arr = [2, 1, 2, 2, 4, 4, 2, 5]; function returnDuplicates(arr) { return arr.reduce(function(dupes, val, i) { if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) { dupes.push(val); } return dupes; }, []); } alert(returnDuplicates(arr)); 

Usando “includes” para testar se o elemento já existe.

 var arr = [1, 1, 4, 5, 5], darr = [], duplicates = []; for(var i = 0; i < arr.length; i++){ if(darr.includes(arr[i]) && !duplicates.includes(arr[i])) duplicates.push(arr[i]) else darr.push(arr[i]); } console.log(duplicates); 
 

Array with duplicates

[1, 1, 4, 5, 5]

Array with distinct elements

[1, 4, 5]

duplicate values are

[1, 5]

O ES6 oferece a estrutura de dados Set, que é basicamente uma matriz que não aceita duplicatas. Com a estrutura de dados Set, há uma maneira muito fácil de encontrar duplicatas em uma matriz (usando apenas um loop).

Aqui está meu código

 function findDuplicate(arr) { var set = new Set(); var duplicates = new Set(); for (let i = 0; i< arr.length; i++) { var size = set.size; set.add(arr[i]); if (set.size === size) { duplicates.add(arr[i]); } } return duplicates; } 

Com o ES6 (ou usando o Babel ou o Typescipt), você pode simplesmente fazer:

 var duplicates = myArray.filter(i => myArray.filter(ii => ii === i).length > 1); 

https://es6console.com/j58euhbt/

Eu acabei de descobrir uma maneira simples de conseguir isso usando um filtro de matriz

  var list = [9, 9, 111, 2, 3, 4, 4, 5, 7]; // Filter 1: to find all duplicates elements var duplicates = list.filter(function(value,index,self) { return self.indexOf(value) !== self.lastIndexOf(value) && self.indexOf(value) === index; }); console.log(duplicates); 

Maneira rápida e elegante usando a desestruturação do object es6 e reduzir

Ele é executado em O (n) (1 iteração sobre o array) e não repete valores que aparecem mais de 2 vezes

 const arr = ['hi', 'hi', 'hi', 'bye', 'bye', 'asd'] const { dup } = arr.reduce( (acc, curr) => { acc.items[curr] = acc.items[curr] ? acc.items[curr] += 1 : 1 if (acc.items[curr] === 2) acc.dup.push(curr) return acc }, { items: {}, dup: [] }, ) console.log(dup) // ['hi', 'bye'] 

Apenas para adicionar alguma teoria ao acima.

Encontrar duplicatas tem um limite inferior de O (n * log (n) no modelo de comparação. Então, teoricamente, você não pode fazer nada melhor que a primeira ordenação, passando pela lista removendo sequencialmente quaisquer duplicatas que encontrar.

Se você quiser encontrar as duplicatas no tempo esperado linear (O (n)), você pode fazer o hash de cada elemento da lista; se houver uma colisão, remova / rotule-a como duplicada e continue.

ES5 apenas (ou seja, ele precisa de um filtro () polyfill para IE8 e abaixo):

 var arrayToFilter = [ 4, 5, 5, 5, 2, 1, 3, 1, 1, 2, 1, 3 ]; arrayToFilter. sort(). filter( function(me,i,arr){ return (i===0) || ( me !== arr[i-1] ); }); 
 var input = ['a', 'b', 'a', 'c', 'c'], duplicates = [], i, j; for (i = 0, j = input.length; i < j; i++) { if (duplicates.indexOf(input[i]) === -1 && input.indexOf(input[i], i+1) !== -1) { duplicates.push(input[i]); } } console.log(duplicates); 

Eu acho que o abaixo é o mais fácil e rápido O (n) caminho para realizar exatamente o que você pediu:

 function getDuplicates( arr ) { var i, value; var all = {}; var duplicates = []; for( i=0; i 

Ou para ES5 ou superior:

 function getDuplicates( arr ) { var all = {}; return arr.reduce(function( duplicates, value ) { if( all[value] ) { duplicates.push(value); all[value] = false; } else if( typeof all[value] == "undefined" ) { all[value] = true; } return duplicates; }, []); } 

Modificando a solução do @RaphaelMontanaro, pegando emprestado do blog do @ Nosredna, aqui está o que você poderia fazer se você quer apenas identificar os elementos duplicados do seu array.

 function identifyDuplicatesFromArray(arr) { var i; var len = arr.length; var obj = {}; var duplicates = []; for (i = 0; i < len; i++) { if (!obj[arr[i]]) { obj[arr[i]] = {}; } else { duplicates.push(arr[i]); } } return duplicates; } 

Obrigado pela solução elegante, @Nosredna!

Eu não gostei da maioria das respostas.

Por quê? Muito complicado, código demais, código ineficiente e muitos não respondem a pergunta, que é encontrar as duplicatas (e não dar um array sem as duplicatas).

Próxima function retorna todas as duplicatas:

 function GetDuplicates(arr) { var i, out=[], obj={}; for (i=0; i < arr.length; i++) obj[arr[i]] == undefined ? obj[arr[i]] ++ : out.push(arr[i]); return out; } 

Porque na maioria das vezes não adianta retornar TODAS as duplicatas, mas apenas informar quais valores duplicados existem. Nesse caso, você retorna um array com duplicatas únicas 😉

 function GetDuplicates(arr) { var i, out=[], obj={}; for (i=0; i < arr.length; i++) obj[arr[i]] == undefined ? obj[arr[i]] ++ : out.push(arr[i]); return GetUnique(out); } function GetUnique(arr) { return $.grep(arr, function(elem, index) { return index == $.inArray(elem, arr); }); } 

Talvez alguém pense o mesmo.

Eu prefiro a maneira de fazer isso.

 function removeDuplicates(links) { return _.reduce(links, function(list, elem) { if (list.indexOf(elem) == -1) { list.push(elem); } return list; }, []); } 

Isso usa sublinhado, mas o Array também tem uma function de reduce

Para resolver o acima em O (n) complexidade de tempo (sem sorting).

 var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7]; var obj={}; for(var i=0;i1){ result.push(Number(key)) // change this to result.push(key) to find duplicate strings in an array } } console.log(result) 

Esta é provavelmente uma das maneiras mais rápidas de remover permanentemente as duplicatas de um array 10x vezes mais rápido do que a maioria das funções aqui. & 78x mais rápido no safari

 function toUnique(a,b,c){//array,placeholder,placeholder b=a.length; while(c=--b)while(c--)a[b]!==a[c]||a.splice(c,1) } var array=[1,2,3,4,5,6,7,8,9,0,1,2,1]; toUnique(array); console.log(array); 
  1. Teste: http://jsperf.com/wgu
  2. Demonstração: http://jsfiddle.net/46S7g/
  3. Mais: https://stackoverflow.com/a/25082874/2450730

Se você não pode ler o código acima, pergunte, leia um livro de javascript ou aqui estão algumas explicações sobre o código mais curto. https://stackoverflow.com/a/21353032/2450730

EDITAR Como indicado nos comentários, esta function retorna uma matriz com uniques, a pergunta, no entanto, pede para encontrar as duplicatas. Nesse caso, uma modificação simples para essa function permite enviar as duplicatas para uma matriz e, em seguida, usar a function anterior toUnique remove as duplicatas das duplicatas.

 function theDuplicates(a,b,c,d){//array,placeholder,placeholder b=a.length,d=[]; while(c=--b)while(c--)a[b]!==a[c]||d.push(a.splice(c,1)) } var array=[1,2,3,4,5,6,7,8,9,0,1,2,1]; toUnique(theDuplicates(array));