Remover valores duplicados da matriz JS

Eu tenho um array JavaScript muito simples que pode ou não conter duplicatas.

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; 

Eu preciso remover as duplicatas e colocar os valores exclusivos em uma nova matriz.

Eu poderia apontar para todos os códigos que eu tentei, mas eu acho que é inútil porque eles não funcionam. Aceito soluções da jQuery também.

Pergunta semelhante:

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

Rápido e sujo usando jQuery:

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; var uniqueNames = []; $.each(names, function(i, el){ if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el); }); 

Maneira “inteligente”, mas ingênua

 uniqueArray = a.filter(function(item, pos) { return a.indexOf(item) == pos; }) 

Basicamente, nós iteramos sobre o array e, para cada elemento, verificamos se a primeira posição desse elemento no array é igual à posição atual. Obviamente, essas duas posições são diferentes para elementos duplicados.

Usando o parâmetro 3rd (“this array”) do retorno de chamada do filtro, podemos evitar o fechamento da variável array:

 uniqueArray = a.filter(function(item, pos, self) { return self.indexOf(item) == pos; }) 

Embora conciso, esse algoritmo não é particularmente eficiente para grandes matrizes (tempo quadrático).

Hashtables para o resgate

 function uniq(a) { var seen = {}; return a.filter(function(item) { return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); } 

É assim que geralmente é feito. A ideia é colocar cada elemento em um hashtable e, em seguida, verificar sua presença instantaneamente. Isso nos dá tempo linear, mas tem pelo menos dois inconvenientes:

  • Como as chaves hash só podem ser strings em JavaScript, esse código não distingue números e “strings numéricas”. Ou seja, uniq([1,"1"]) retornará apenas [1]
  • pelo mesmo motivo, todos os objects serão considerados iguais: uniq([{foo:1},{foo:2}]) retornará apenas [{foo:1}] .

Dito isso, se seus arrays contiverem apenas primitivos e você não se importar com os tipos (por exemplo, sempre são números), essa solução é ideal.

O melhor dos dois mundos

Uma solução universal combina as duas abordagens: usa pesquisas de hash para primitivos e pesquisa linear de objects.

 function uniq(a) { var prims = {"boolean":{}, "number":{}, "string":{}}, objs = []; return a.filter(function(item) { var type = typeof item; if(type in prims) return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true); else return objs.indexOf(item) >= 0 ? false : objs.push(item); }); } 

classificar | uniq

Outra opção é classificar primeiro o array e, em seguida, remover cada elemento igual ao precedente:

 function uniq(a) { return a.sort().filter(function(item, pos, ary) { return !pos || item != ary[pos - 1]; }) } 

Novamente, isso não funciona com objects (porque todos os objects são iguais para sort ). Além disso, mudamos silenciosamente o array original como um efeito colateral – não é bom! No entanto, se a sua input já estiver ordenada, este é o caminho a seguir (apenas remova a sort acima).

Exclusivo por …

Às vezes, é desejável uniquificar uma lista com base em alguns critérios além da igualdade, por exemplo, para filtrar objects diferentes, mas compartilhar alguma propriedade. Isso pode ser feito elegantemente, passando um retorno de chamada. Esse retorno de chamada “chave” é aplicado a cada elemento e os elementos com “chaves” iguais são removidos. Como se espera que a key retorne uma tabela hash primitiva, ela funcionará bem aqui:

 function uniqBy(a, key) { var seen = {}; return a.filter(function(item) { var k = key(item); return seen.hasOwnProperty(k) ? false : (seen[k] = true); }) } 

Uma key() particularmente útil key() é JSON.stringify que removerá objects que são fisicamente diferentes, mas “parecem” iguais:

 a = [[1,2,3], [4,5,6], [1,2,3]] b = uniqBy(a, JSON.stringify) console.log(b) // [[1,2,3], [4,5,6]] 

Se a key não for primitiva, você precisará recorrer à pesquisa linear:

 function uniqBy(a, key) { var index = []; return a.filter(function (item) { var k = key(item); return index.indexOf(k) >= 0 ? false : index.push(k); }); } 

ou use o object Set no ES6:

 function uniqBy(a, key) { var seen = new Set(); return a.filter(item => { var k = key(item); return seen.has(k) ? false : seen.add(k); }); } 

(Algumas pessoas preferem !seen.has(k) && seen.add(k) vez de seen.has(k) ? false : seen.add(k) ).

Bibliotecas

Tanto o sublinhado quanto o Lo-Dash fornecem methods uniq . Seus algoritmos são basicamente semelhantes ao primeiro snippet acima e resumem-se a isto:

 var result = []; a.forEach(function(item) { if(result.indexOf(item) < 0) { result.push(item); } }); 

Isso é quadrático, mas há itens adicionais interessantes, como o envolvimento de indexOf nativo, a capacidade de uniqify por uma chave ( iteratee em sua linguagem) e otimizações para matrizes já classificadas.

Se você está usando jQuery e não suporta nada sem um dólar antes, é assim:

  $.uniqArray = function(a) { return $.grep(a, function(item, pos) { return $.inArray(item, a) === pos; }); } 

que é, novamente, uma variação do primeiro trecho.

atuação

Chamadas de funções são caras em Javascript, portanto as soluções acima, tão concisas quanto são, não são particularmente eficientes. Para desempenho máximo, substitua o filter por um loop e elimine outras chamadas de function:

 function uniq_fast(a) { var seen = {}; var out = []; var len = a.length; var j = 0; for(var i = 0; i < len; i++) { var item = a[i]; if(seen[item] !== 1) { seen[item] = 1; out[j++] = item; } } return out; } 

Este pedaço de código feio faz o mesmo que o trecho nº 3 acima, mas uma ordem de grandeza mais rápida (a partir de 2017 é apenas duas vezes mais rápido - o pessoal da JS está fazendo um ótimo trabalho!)

 function uniq(a) { var seen = {}; return a.filter(function(item) { return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); } function uniq_fast(a) { var seen = {}; var out = []; var len = a.length; var j = 0; for(var i = 0; i < len; i++) { var item = a[i]; if(seen[item] !== 1) { seen[item] = 1; out[j++] = item; } } return out; } ///// var r = [0,1,2,3,4,5,6,7,8,9], a = [], LEN = 1000, LOOPS = 1000; while(LEN--) a = a.concat(r); var d = new Date(); for(var i = 0; i < LOOPS; i++) uniq(a); document.write('
uniq, ms/loop: ' + (new Date() - d)/LOOPS) var d = new Date(); for(var i = 0; i < LOOPS; i++) uniq_fast(a); document.write('
uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

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.

Uniq reduz enquanto mantém o pedido existente

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; var uniq = names.reduce(function(a,b){ if (a.indexOf(b) < 0 ) a.push(b); return a; },[]); console.log(uniq, names) // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ] // one liner return names.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]); 

Uniq mais rápido com triagem

Existem provavelmente formas mais rápidas, mas esta é bastante decente.

 var uniq = names.slice() // slice makes copy of array before sorting it .sort(function(a,b){ return a > b; }) .reduce(function(a,b){ if (a.slice(-1)[0] !== b) a.push(b); // slice(-1)[0] means last item in array without removing it (like .pop()) return a; },[]); // this empty array becomes the starting value for a // one liner return names.slice().sort(function(a,b){return a > b}).reduce(function(a,b){if (a.slice(-1)[0] !== b) a.push(b);return a;},[]); 

Atualização 2015: versão ES6:

No ES6 você tem Sets and Spread, o que torna muito fácil e eficiente remover todas as duplicatas:

 var uniq = [ ...new Set(names) ]; // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ] 

Ordenar com base na ocorrência:

Alguém perguntou sobre como ordenar os resultados com base em quantos nomes exclusivos existem:

 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 sorted = Object.keys(uniq).sort((a, b) => uniq[a] < uniq[b]) console.log(sorted) 

Baunilha JS: Remover duplicatas usando um object como um conjunto

Você sempre pode tentar colocá-lo em um object e, em seguida, iterar por meio de suas chaves:

 function remove_duplicates(arr) { var obj = {}; var ret_arr = []; for (var i = 0; i < arr.length; i++) { obj[arr[i]] = true; } for (var key in obj) { ret_arr.push(key); } return ret_arr; } 

Baunilha JS: Remover duplicatas, rastreando valores já vistos (ordem segura)

Ou, para uma versão segura, use um object para armazenar todos os valores vistos anteriormente e verifique os valores antes de adicioná-los a uma matriz.

 function remove_duplicates_safe(arr) { var seen = {}; var ret_arr = []; for (var i = 0; i < arr.length; i++) { if (!(arr[i] in seen)) { ret_arr.push(arr[i]); seen[arr[i]] = true; } } return ret_arr; } 

ECMAScript 6: Use a nova estrutura de dados Set (segura para pedidos)

O ECMAScript 6 adiciona o novo Set Data-Structure, que permite armazenar valores de qualquer tipo. Set.values retorna elementos no pedido de inserção.

 function remove_duplicates_es6(arr) { let s = new Set(arr); let it = s.values(); return Array.from(it); } 

Exemplo de uso:

 a = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; b = remove_duplicates(a); // b: // ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"] c = remove_duplicates_safe(a); // c: // ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"] d = remove_duplicates_es6(a); // d: // ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"] 

Use Underscore.js

É uma biblioteca com várias funções para manipular matrizes.

É o empate para combinar com o smoking do jQuery e os suspensórios do Backbone.js.

_.uniq

_.uniq(array, [isSorted], [iterator]) Alias: exclusivo
Produz uma versão livre da duplicata da matriz , usando === para testar a igualdade de objects. Se você souber antecipadamente que a matriz está classificada, a passagem true para isSorted executará um algoritmo muito mais rápido. Se você deseja calcular itens exclusivos com base em uma transformação, passe uma function de iterador .

Exemplo

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; alert(_.uniq(names, false)); 

Nota: Lo-Dash (um concorrente de sublinhado ) também oferece uma implementação .uniq comparável.

Uma versão de linha única usando o filtro de matriz e as funções indexOf:

 arr = arr.filter (function (value, index, array) { return array.indexOf (value) == index; }); 

Você pode simplesmente fazer isso em JavaScript, com a ajuda do segundo parâmetro – index do método de filter :

 var a = [2,3,4,5,5,4]; a.filter(function(value, index){ return a.indexOf(value) == index }); 

ou em suma

 a.filter((v,i) => a.indexOf(v) == i) 

Uma linha:

 let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy']; let dup = [...new Set(names)]; console.log(dup); 

A maneira mais concisa de remover duplicatas de uma matriz usando funções javascript nativas é usar uma sequência como a abaixo:

 vals.sort().reduce(function(a, b){ if (b != a[0]) a.unshift(b); return a }, []) 

não há necessidade de slice nem indexOf dentro da function reduce, como eu já vi em outros exemplos! faz sentido usá-lo junto com uma function de filtro embora:

 vals.filter(function(v, i, a){ return i == a.indexOf(v) }) 

Ainda outra maneira ES6 (2015) de fazer isso que já funciona em alguns navegadores é:

 Array.from(new Set(vals)) 

ou até mesmo usando o operador de spread :

 [...new Set(vals)] 

Felicidades!

Vá para este:

 var uniqueArray = duplicateArray.filter(function(elem, pos) { return duplicateArray.indexOf(elem) == pos; }); 

Agora uniqueArray não contém duplicatas.

Mais simples que eu já corri até agora. Em es6.

  var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl", "Mike", "Nancy"] var noDupe = Array.from(new Set(names)) 

https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Set

use Array.filter() assim

 var actualArr = ['Apple', 'Apple', 'Banana', 'Mango', 'Strawberry', 'Banana']; console.log('Actual Array: ' + actualArr); var filteredArr = actualArr.filter(function(item, index) { if (actualArr.indexOf(item) == index) return item; }); console.log('Filtered Array: ' + filteredArr); 

Eu tinha feito uma comparação detalhada de remoção de dupes em alguma outra questão, mas tendo notado que este é o lugar real, eu só queria compartilhá-lo aqui também.

Eu acredito que esta é a melhor maneira de fazer isso

 var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200], reduced = Object.keys(myArray.reduce((p,c) => (p[c] = true,p),{})); console.log(reduced); 

O seguinte é mais de 80% mais rápido do que o método jQuery listado (veja os testes abaixo). É uma resposta de uma pergunta semelhante há alguns anos atrás. Se eu me deparar com a pessoa que originalmente propôs, vou postar crédito. Puro JS.

 var temp = {}; for (var i = 0; i < array.length; i++) temp[array[i]] = true; var r = []; for (var k in temp) r.push(k); return r; 

Minha comparação de caso de teste: http://jsperf.com/remove-duplicate-array-tests

Aqui está uma resposta simples para a pergunta.

 var names = ["Alex","Tony","James","Suzane", "Marie", "Laurence", "Alex", "Suzane", "Marie", "Marie", "James", "Tony", "Alex"]; var uniqueNames = []; for(var i in names){ if(uniqueNames.indexOf(names[i]) === -1){ uniqueNames.push(names[i]); } } 

No ECMAScript 6 (também conhecido como ECMAScript 2015), o Set pode ser usado para filtrar duplicados. Em seguida, ele pode ser convertido de volta em um array usando o operador spread .

 var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"], unique = [...new Set(names)]; 

Uma técnica simples, mas eficaz, é usar o método de filter em combinação com a function(value, index){ return this.indexOf(value) == index } filtro function(value, index){ return this.indexOf(value) == index } .

Exemplo de código:

 var data = [2,3,4,5,5,4]; var filter = function(value, index){ return this.indexOf(value) == index }; var filteredData = data.filter(filter, data ); document.body.innerHTML = '
' + JSON.stringify(filteredData, null, '\t') + '

';

Solução 1

 Array.prototype.unique = function() { var a = []; for (i = 0; i < this.length; i++) { var current = this[i]; if (a.indexOf(current) < 0) a.push(current); } return a; } 

Solução 2 (usando Set)

 Array.prototype.unique = function() { return Array.from(new Set(this)); } 

Teste

 var x=[1,2,3,3,2,1]; x.unique() //[1,2,3] 

atuação

Quando eu testei ambas as implementações (com e sem Set) para desempenho no chrome, descobri que o que possui o Set é muito mais rápido!

 Array.prototype.unique1 = function() { var a = []; for (i = 0; i < this.length; i++) { var current = this[i]; if (a.indexOf(current) < 0) a.push(current); } return a; } Array.prototype.unique2 = function() { return Array.from(new Set(this)); } var x=[]; for(var i=0;i<10000;i++){ x.push("x"+i);x.push("x"+(i+1)); } console.time("unique1"); console.log(x.unique1()); console.timeEnd("unique1"); console.time("unique2"); console.log(x.unique2()); console.timeEnd("unique2"); 

As respostas principais têm complexidade de O(n²) , mas isso pode ser feito apenas com O(n) usando um object como um hash:

 function getDistinctArray(arr) { var dups = {}; return arr.filter(function(el) { var hash = el.valueOf(); var isDup = dups[hash]; dups[hash] = true; return !isDup; }); } 

This will work for strings, numbers, and dates. If your array contains complex objects (ie, they have to be compared with === ), the above solution won’t work. You can get an O(n) implementation for objects by setting a flag on the object itself:

 function getDistinctObjArray(arr) { var distinctArr = arr.filter(function(el) { var isDup = el.inArray; el.inArray = true; return !isDup; }); distinctArr.forEach(function(el) { delete el.inArray; }); return distinctArr; } 

here is the simple method without any special libraries are special function,

 name_list = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; get_uniq = name_list.filter(function(val,ind) { return name_list.indexOf(val) == ind; }) console.log("Original name list:"+name_list.length, name_list) console.log("\n Unique name list:"+get_uniq.length, get_uniq) 

Apart from being a simpler, more terse solution than the current answers (minus the future-looking ES6 ones), I perf tested this and it was much faster as well:

 var uniqueArray = dupeArray.filter(function(item, i, self){ return self.lastIndexOf(item) == i; }); 

One caveat: Array.lastIndexOf() was added in IE9, so if you need to go lower than that, you’ll need to look elsewhere.

So the options is:

 let a = [11,22,11,22]; let b = [] b = [ ...new Set(a) ]; // b = [11, 22] b = Array.from( new Set(a)) // b = [11, 22] b = a.filter((val,i)=>{ return a.indexOf(val)==i }) // b = [11, 22] 

Generic Functional Approach

Here is a generic and strictly functional approach with ES2015:

 // small, reusable auxiliary functions const apply = f => a => f(a); const flip = f => b => a => f(a) (b); const uncurry = f => (a, b) => f(a) (b); const push = x => xs => (xs.push(x), xs); const foldl = f => acc => xs => xs.reduce(uncurry(f), acc); const some = f => xs => xs.some(apply(f)); // the actual de-duplicate function const uniqueBy = f => foldl( acc => x => some(f(x)) (acc) ? acc : push(x) (acc) ) ([]); // comparators const eq = y => x => x === y; // string equality case insensitive :D const seqCI = y => x => x.toLowerCase() === y.toLowerCase(); // mock data const xs = [1,2,3,1,2,3,4]; const ys = ["a", "b", "c", "A", "B", "C", "D"]; console.log( uniqueBy(eq) (xs) ); console.log( uniqueBy(seqCI) (ys) ); 
 $(document).ready(function() { var arr1=["dog","dog","fish","cat","cat","fish","apple","orange"] var arr2=["cat","fish","mango","apple"] var uniquevalue=[]; var seconduniquevalue=[]; var finalarray=[]; $.each(arr1,function(key,value){ if($.inArray (value,uniquevalue) === -1) { uniquevalue.push(value) } }); $.each(arr2,function(key,value){ if($.inArray (value,seconduniquevalue) === -1) { seconduniquevalue.push(value) } }); $.each(uniquevalue,function(ikey,ivalue){ $.each(seconduniquevalue,function(ukey,uvalue){ if( ivalue == uvalue) { finalarray.push(ivalue); } }); }); alert(finalarray); }); 

Here is very simple for understanding and working anywhere (even in PhotoshopScript) code. Check it!

 var peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"); peoplenames = unique(peoplenames); alert(peoplenames); function unique(array){ var len = array.length; for(var i = 0; i < len; i++) for(var j = i + 1; j < len; j++) if(array[j] == array[i]){ array.splice(j,1); j--; len--; } return array; } //*result* peoplenames == ["Mike","Matt","Nancy","Adam","Jenny","Carl"] 
 for (i=0; i 

This is probably one of the fastest way to remove permanently the duplicates from an array 10x times faster than the most functions here.& 78x faster in 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) } 
  1. Test: http://jsperf.com/wgu
  2. Demo: http://jsfiddle.net/46S7g/
  3. More: https://stackoverflow.com/a/25082874/2450730

if you can’t read the code above ask, read a javascript book or here are some explainations about shorter code. https://stackoverflow.com/a/21353032/2450730

If by any chance you were using

D3.js

Você poderia fazer

 d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"] 

https://github.com/mbostock/d3/wiki/Arrays#set_values

https://jsfiddle.net/2w0k5tz8/

 function remove_duplicates(array_){ var ret_array = new Array(); for (var a = array_.length - 1; a >= 0; a--) { for (var b = array_.length - 1; b >= 0; b--) { if(array_[a] == array_[b] && a != b){ delete array_[b]; } }; if(array_[a] != undefined) ret_array.push(array_[a]); }; return ret_array; } console.log(remove_duplicates(Array(1,1,1,2,2,2,3,3,3))); 

Loop through, remove duplicates, and create a clone array place holder because the array index will not be updated.

Loop backward for better performance ( your loop wont need to keep checking the length of your array)

This was just another solution but different than the rest.

 function diffArray(arr1, arr2) { var newArr = arr1.concat(arr2); newArr.sort(); var finalArr = []; for(var i = 0;i