Eu tenho uma matriz de números que eu preciso ter certeza de que são únicos. Encontrei o trecho de código abaixo na internet e ele funciona muito bem até que o array tenha zero. Encontrei esse outro script aqui no Stack Overflow que se parece quase exatamente com ele, mas não falha.
Então, para me ajudar a aprender, alguém pode me ajudar a determinar onde o script do protótipo está errado?
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;
}
Mais respostas da pergunta duplicada:
Pergunta semelhante:
javascript
arrays
unique
Mottie
fonte
fonte
o
=object
,a
=array
,i
=index
ee
= umm, algo: PRespostas:
Com o JavaScript 1.6 / ECMAScript 5, você pode usar o
filter
método nativo de uma matriz da seguinte maneira para obter uma matriz com valores exclusivos:O método nativo
filter
percorrerá a matriz e deixará apenas as entradas que passam pela função de retorno de chamada fornecidaonlyUnique
.onlyUnique
verifica se o valor fornecido é o primeiro a ocorrer. Caso contrário, deve ser uma duplicata e não será copiada.Esta solução funciona sem nenhuma biblioteca extra como jQuery ou prototype.js.
Também funciona para matrizes com tipos de valor misto.
Para navegadores antigos (<IE9), que não suportam os métodos nativos
filter
eindexOf
pode encontrar arounds trabalho na documentação MDN para filtro e indexOf .Se você deseja manter a última ocorrência de um valor, substitua-o
indexOf
porlastIndexOf
.Com o ES6, pode ser reduzido para isso:
Obrigado a Camilo Martin pela dica no comentário.
O ES6 possui um objeto nativo
Set
para armazenar valores exclusivos. Para obter uma matriz com valores exclusivos, você pode fazer isso agora:O construtor de
Set
pega um objeto iterável, como Matriz, e o operador de dispersão...
transforma o conjunto novamente em uma Matriz. Obrigado a Lukas Liese pela dica no comentário.fonte
['a', 1, 'a', 2, '1']
você receberia['a', 1, 2]
. Mas não é isso que eu esperava. BTW, muito mais lento é muito relativo..filter((v,i,a)=>a.indexOf(v)==i)
(notação de seta gorda).let unique_values = [...new Set(random_array)];
developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…Resposta atualizada para ES6 / ES2015 : Usando o conjunto , a solução de linha única é:
Que retorna
Como le_m sugeriu, isso também pode ser reduzido usando o operador spread , como
fonte
Array.from(new Set([[1,2],[1,2],[1,2,3]]))
myArray.filter((v, i, a) => a.indexOf(v) === i);
?Set
objetos e adicionar objetos em vez de valores primitivos, ele conterá referências exclusivas aos objetos. Assim, o sets
inlet s = new Set([{Foo:"Bar"}, {Foo:"Bar"}]);
retornará this:Set { { Foo: 'Bar' }, { Foo: 'Bar' } }
que é umSet
objeto com referências únicas a objetos que contêm os mesmos valores. Se você escreverlet o = {Foo:"Bar"};
e, em seguida, criar um conjunto com duas referências assim:let s2 = new Set([o,o]);
, então s2 seráSet { { Foo: 'Bar' } }
new Set
's troféuSei que esta pergunta já tem mais de 30 respostas. Mas li todas as respostas existentes primeiro e fiz minha própria pesquisa.
Dividi todas as respostas para 4 soluções possíveis:
[...new Set( [1, 1, 2] )];
{ }
para evitar duplicatas[ ]
filter + indexOf
Aqui estão exemplos de códigos encontrados nas respostas:
Use o novo recurso ES6:
[...new Set( [1, 1, 2] )];
Use objeto
{ }
para evitar duplicatasUsar matriz auxiliar
[ ]
Usar
filter + indexOf
E me perguntei qual é o mais rápido. Fiz uma amostra do Google Sheet para testar funções. Nota: O ECMA 6 não está disponível no Planilhas Google, então não posso testá-lo.
Aqui está o resultado dos testes:
Eu esperava ver que o código usando o objeto
{ }
vencerá porque ele usa hash. Estou feliz que os testes tenham mostrado melhores resultados para esse algoritmo no Chrome e no IE. Obrigado a @rab pelo código .fonte
Você também pode usar underscore.js .
que retornará:
fonte
array = [...new Set(array)]
One Liner, JavaScript puro
Com sintaxe ES6
list = list.filter((x, i, a) => a.indexOf(x) == i)
Com sintaxe ES5
Compatibilidade do Navegador : IE9 +
fonte
Desde então, encontrei um bom método que usa jQuery
Nota: Este código foi retirado do post de soco de pato de Paul Irish - eu esqueci de dar crédito: P
fonte
Solução mais curta com ES6:
[...new Set( [1, 1, 2] )];
Ou se você deseja modificar o protótipo Array (como na pergunta original):
No momento, o EcmaScript 6 é implementado apenas parcialmente em navegadores modernos (agosto de 2015), mas o Babel se tornou muito popular ao transpilar o ES6 (e até o ES7) de volta para o ES5. Dessa forma, você pode escrever o código ES6 hoje!
Se você está se perguntando o que isso
...
significa, é chamado de operador de propagação . No MDN : «O operador spread permite que uma expressão seja expandida em locais onde são esperados múltiplos argumentos (para chamadas de função) ou múltiplos elementos (para literais de matriz)». Como um conjunto é iterável (e pode ter apenas valores exclusivos), o operador de expansão expandirá o conjunto para preencher a matriz.Recursos para aprender ES6:
fonte
a = [...Set(a)]
, mas, de qualquer forma, este é apenas o Firefox, por enquanto.require ( "core-js/fn/array/from" );
[...Set(['a', 1, 'a', 2, '1'])]
irá lançar um TypeError, por isso ainda é aconselhável manter onew
:[...new Set(['a', 1, 'a', 2, '1'])]
Solução mais simples:
Ou:
fonte
A maneira mais simples e rápida (no Chrome) de fazer isso:
Simplesmente percorre todos os itens da matriz, testa se esse item já está na lista e, se não estiver, envie para a matriz retornada.
De acordo com o jsPerf, essa função é a mais rápida que encontrei em qualquer lugar - fique à vontade para adicionar a sua.
A versão sem protótipo:
Ordenação
Quando também é necessário classificar a matriz, o seguinte é o mais rápido:
ou não protótipo:
Isso também é mais rápido que o método acima na maioria dos navegadores não-chrome.
fonte
unique
função tem complexidade O (n ^ 2), enquanto o algoritmogetUnique
é O (n). O primeiro pode ser mais rápido em pequenos conjuntos de dados, mas como você pode argumentar com a matemática :) Você pode garantir que o último seja mais rápido se você executá-lo em uma variedade de, por exemplo, 1e5 itens exclusivosSOMENTE DESEMPENHO! esse código é provavelmente 10 vezes mais rápido que todos os códigos aqui * funciona em todos os navegadores e também tem o menor impacto na memória .... e mais
se você não precisar reutilizar o array antigo, faça as outras operações necessárias antes de convertê-lo em exclusivo aqui, provavelmente é a maneira mais rápida de fazer isso, também muito curta.
então você pode tentar isso
Eu vim com essa função lendo este artigo ...
http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/
Eu não gosto do loop for. ele tem muitos parâmetros. eu gosto do loop while--. enquanto é o loop mais rápido em todos os navegadores, exceto no que todos gostamos tanto ... chrome.
de qualquer maneira eu escrevi a primeira função que usa while.E sim, é um pouco mais rápido que a função encontrada no article.but não é suficiente.
unique2()
próximo passo use js modernos.
Object.keys
Substituí o outro por loop com Object.keys do js1.7 ... um pouco mais rápido e mais curto (no chrome 2x mais rápido);). Insuficiente!.unique3()
.Neste ponto, eu estava pensando sobre o que eu realmente preciso em MINHA função única. não preciso da matriz antiga, quero uma função rápida. então eu usei 2 enquanto loops + emenda.
unique4()
Inútil dizer que fiquei impressionado.
chrome: as 150.000 operações usuais por segundo saltaram para 1.800.000 operações por segundo.
ou seja: 80.000 op / s vs 3.500.000 op / s
ios: 18.000 op / s vs 170.000 op / s
safari: 80.000 op / s vs 6.000.000 op / s
Prova http://jsperf.com/wgu ou melhor, use console.time ... microtime ... qualquer que seja
unique5()
é apenas para mostrar o que acontece se você deseja manter a matriz antiga.Não use
Array.prototype
se você não sabe o que está fazendo. Eu apenas fiz um monte de cópia e passado. UseObject.defineProperty(Array.prototype,...,writable:false,enumerable:false})
se você deseja criar um protótipo nativo. Exemplo: https://stackoverflow.com/a/20463021/2450730Demo http://jsfiddle.net/46S7g/
NOTA: sua matriz antiga é destruída / torna-se única após esta operação.
se você não consegue ler o código acima, pergunte, leia um livro javascript ou aqui estão algumas explicações sobre códigos mais curtos. https://stackoverflow.com/a/21353032/2450730
alguns estão usando
indexOf
... não ... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfhpara matrizes vazias
fonte
Muitas das respostas aqui podem não ser úteis para iniciantes. Se a remoção de duping de uma matriz for difícil, eles realmente saberão sobre a cadeia de protótipos ou mesmo sobre o jQuery?
Nos navegadores modernos, uma solução limpa e simples é armazenar dados em um conjunto , projetado para ser uma lista de valores exclusivos.
O
Array.from
é útil para converter parte de trás Set para uma matriz para que você tenha acesso fácil a todos os métodos impressionantes (características) que as matrizes têm. Existem também outras maneiras de fazer a mesma coisa. Mas você pode não precisarArray.from
, pois o Sets possui muitos recursos úteis, como o forEach .Se você precisar dar suporte ao Internet Explorer antigo e, portanto, não puder usar o Set, uma técnica simples é copiar itens para uma nova matriz e verificar com antecedência se eles já estão na nova matriz.
Para tornar isso instantaneamente reutilizável, vamos colocá-lo em uma função.
Então, para se livrar das duplicatas, faríamos agora isso.
A
deduplicate(cars)
parte se torna a coisa que chamamos de resultado quando a função é concluída.Apenas passe o nome de qualquer array que você desejar.
fonte
fonte
push
o elemento na matriz em vez de usá-loconcat
? Eu tentei usar push e falhou. Estou procurando uma explicação.[0,1,2,0,3,2,1,5].reduce((prev, cur) => ~prev.indexOf(cur) ? prev : prev.concat([cur]), []);
NaN
-amigávelPodemos fazer isso usando conjuntos ES6:
// A saída será
fonte
Este protótipo
getUnique
não está totalmente correto, porque se eu tiver um Array como:["1",1,2,3,4,1,"foo"]
ele retornará["1","2","3","4"]
e"1"
é string e1
é um número inteiro; Eles são diferentes.Aqui está uma solução correta:
usando:
O acima irá produzir
["1",2,3,4,1,"foo"]
.fonte
$foo = 'bar'
é a maneira do PHP de declarar variáveis. Funcionará em javascript, mas criará um global implícito e geralmente não deve ser feito.$foo
é a maneira de declarar variáveis em javascript enquanto na verdadevar foo
é.Sem estender Array.prototype (é considerado uma prática ruim) ou usar jquery / underscore, você pode simplesmente
filter
a matriz.Mantendo a última ocorrência:
ou primeira ocorrência:
Bem, é apenas javascript ECMAScript 5+, o que significa apenas IE9 +, mas é bom para o desenvolvimento em HTML / JS nativo (Windows Store App, Firefox OS, Sencha, Phonegap, Titanium, ...).
fonte
filter
. Na página MDN, eles têm uma implementação para o Internet Explorer, quero dizer, navegadores mais antigos. Também: JS 1.6 refere-se apenas ao motor js do Firefox, mas a coisa certa a dizer que é que é ECMAScript 5.Magia
O (n) desempenho ; assumimos que sua matriz está em
a
et={}
. Explicação aqui (+ Jeppe impr.)Mostrar snippet de código
fonte
in
operador fora da outra construção que não ofor
loop: P) - Obrigado - agradeço e darei +2 às suas outras boas respostas .t
que permanece viva após a filtragem ... ??fonte
Se você estiver usando a estrutura Prototype, não há necessidade de fazer loops 'for', você pode usar http://www.prototypejs.org/api/array/uniq assim:
O que produzirá uma matriz duplicada sem duplicatas. Me deparei com sua pergunta procurando um método para contar registros de matriz distintos, para depois
eu usei
e houve o meu resultado simples. ps Desculpe se eu digitei algo errado
editar: se você quiser escapar de registros indefinidos, poderá adicionar
antes, assim:
fonte
Agora, usando conjuntos, você pode remover duplicatas e convertê-las novamente na matriz.
Outra solução é usar classificação e filtro
fonte
Isso
0
ocorre porque é um valor falso no JavaScript.this[i]
será falso se o valor da matriz for 0 ou qualquer outro valor falso.fonte
fonte
o
vez de apenas a1
, embora a comparação de igualdade ainda seja sequencial (embora, dentre todas as possíveis igualdade de Javascript, isso não pareça irracional).Eu tive um problema um pouco diferente, em que precisei remover objetos com propriedades de identificação duplicadas de uma matriz. isso funcionou.
fonte
A resposta mais simples é:
fonte
Não sei por que Gabriel Silveira escreveu a função dessa maneira, mas uma forma mais simples que funciona para mim da mesma forma e sem a minificação é:
ou no CoffeeScript:
fonte
Se você concorda com dependências extras ou já possui uma das bibliotecas da sua base de código, pode remover duplicatas de uma matriz no local usando LoDash (ou Sublinhado).
Uso
Se você ainda não o possui na sua base de código, instale-o usando o npm:
Em seguida, use-o da seguinte maneira:
Fora:
fonte
Isso foi muito respondido, mas não atendeu minha necessidade particular.
Muitas respostas são assim:
Mas isso não funciona para matrizes de objetos complexos.
Digamos que temos uma matriz como esta:
Se queremos os objetos com nomes exclusivos, devemos usar em
array.prototype.findIndex
vez dearray.prototype.indexOf
:fonte
De Shamasis Bhattacharya blog do (complexidade O (2n) tempo):
No blog de Paul Irish : aprimoramento no JQuery
.unique()
:fonte
Localizando valores exclusivos de matriz em método simples
fonte
Parece que perdemos a resposta de Rafael , que permaneceu como resposta aceita por alguns anos. Essa foi (pelo menos em 2017) a solução com melhor desempenho se você não tiver uma matriz de tipo misto :
Se você fazer tem uma matriz de tipo misto, você pode serializar a chave de hash:
fonte
Para resolver o problema de maneira inversa, pode ser útil não duplicar enquanto você carrega sua matriz, da maneira que o objeto Set faria, mas ainda não está disponível em todos os navegadores. Ele economiza memória e é mais eficiente se você precisar examinar o conteúdo várias vezes.
Amostra:
Da-te
set = [1,3,4,2]
fonte