Eu gostaria de comparar duas matrizes ... idealmente, eficientemente. Nada extravagante, apenas true
se eles são idênticos, e false
se não. Não é de surpreender que o operador de comparação não pareça funcionar.
var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2); // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2)); // Returns true
A codificação JSON de cada matriz faz, mas existe uma maneira mais rápida ou "melhor" de simplesmente comparar matrizes sem precisar iterar cada valor?
javascript
arrays
json
Julian H. Lam
fonte
fonte
([] == []) == false
.Respostas:
Para comparar matrizes, faça um loop entre elas e compare todos os valores:
Comparando matrizes:
Uso:
Você pode dizer " Mas é muito mais rápido comparar seqüências de caracteres - sem loops ... " bem, então você deve observar que existem loops. Primeiro loop recursivo que converte Array em string e segundo, que compara duas strings. Portanto, esse método é mais rápido que o uso de string .
Acredito que grandes quantidades de dados sempre devem ser armazenadas em matrizes, não em objetos. No entanto, se você usar objetos, eles também poderão ser comparados parcialmente.
Aqui está como:
Comparando objetos:
Eu afirmei acima, que duas instâncias de objetos nunca serão iguais, mesmo que contenham os mesmos dados no momento:
Isso tem um motivo, pois pode haver, por exemplo, variáveis privadas dentro de objetos.
No entanto, se você apenas usar a estrutura de objetos para conter dados, a comparação ainda será possível:
No entanto, lembre-se de que este serve para comparar JSON como dados, não instâncias de classe e outras coisas. Se você deseja comparar mais objetos complicados, veja esta resposta e sua função é longa .
Para fazer isso funcionar,
Array.equals
você deve editar um pouco a função original:Fiz uma pequena ferramenta de teste para ambas as funções .
Bônus: matrizes aninhadas com
indexOf
econtains
Samy Bencherif preparou funções úteis para o caso de você estar procurando um objeto específico em matrizes aninhadas, disponíveis aqui: https://jsfiddle.net/SamyBencherif/8352y6yw/
fonte
this[i] !== array[i]
vez de!=
.equals
vez decompare
. Pelo menos no .NET, compare geralmente retorna um int assinado indicando qual objeto é maior que o outro. Consulte: Comparer.Compare .Embora isso funcione apenas para matrizes escalares (veja a nota abaixo), é curto:
Rr, no ECMAScript 6 / CoffeeScript / TypeScript com funções de seta:
(Nota: 'escalar' aqui significa valores que podem ser comparados diretamente usando
===
. Portanto: números, seqüências de caracteres, objetos por referência, funções por referência. Consulte a referência MDN para obter mais informações sobre os operadores de comparação).ATUALIZAR
Pelo que li nos comentários, classificar a matriz e comparar pode fornecer um resultado preciso:
Por exemplo:
Então o código acima daria
true
fonte
a1.length==a2.length && a1.every((v,i)=>a2.includes(v))
:var a1 =[1,2,3], a2 = [3,2,1];
(var a1 =[1,3,3], a2 = [1,1,3];
não funcionará como esperado)Eu gosto de usar a biblioteca Underscore para projetos de codificação pesada de array / objeto ... no Underscore e no Lodash, se você estiver comparando arrays ou objetos, ele se parece com o seguinte:
fonte
_.isEqual([1,2,3], [2,1,3]) => false
isEqual
funcionalidade, sempre poderá usar o módulo_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Acho que é a maneira mais simples de fazer isso usando JSON stringify, e pode ser a melhor solução em algumas situações:
Isso converte os objetos
a1
ea2
em seqüências de caracteres para que possam ser comparados. A ordem é importante na maioria dos casos, pois isso pode classificar o objeto usando um algoritmo de classificação mostrado em uma das respostas acima.Observe que você não está mais comparando o objeto, mas a representação de string do objeto. Pode não ser exatamente o que você deseja.
fonte
Não está claro o que você quer dizer com "idêntico". Por exemplo, as matrizes
a
eb
abaixo são idênticas (observe as matrizes aninhadas)?Aqui está uma função de comparação de matriz otimizada que compara elementos correspondentes de cada matriz, por sua vez, usando igualdade estrita e não faz comparação recursiva de elementos de matriz que são matrizes, o que significa que, para o exemplo acima,
arraysIdentical(a, b)
retornariafalse
. Funciona no caso geral, que asjoin()
soluções baseadas em JSON e não:fonte
true
. A resposta explica que não. Se você precisar comparar matrizes aninhadas, poderá adicionar facilmente uma verificação recursiva.O Caminho Prático
Eu acho errado dizer que uma implementação específica é "The Right Way ™" se for apenas "certa" ("correta") em contraste com uma solução "errada". A solução de Tomáš é uma clara melhoria na comparação de matrizes baseada em strings, mas isso não significa que seja objetivamente "correto". O que é certo, afinal? É o mais rápido? É o mais flexível? É o mais fácil de entender? É o mais rápido para depurar? Utiliza menos operações? Isso tem algum efeito colateral? Nenhuma solução pode ter o melhor de todas as coisas.
Tomás poderia dizer que sua solução é rápida, mas eu também diria que é desnecessariamente complicado. Ele tenta ser uma solução completa que funciona para todas as matrizes, aninhadas ou não. De fato, ele aceita mais do que apenas matrizes como entrada e ainda tenta dar uma resposta "válida".
Os genéricos oferecem reutilização
Minha resposta abordará o problema de maneira diferente. Começarei com um
arrayCompare
procedimento genérico que se preocupa apenas em percorrer as matrizes. A partir daí, criaremos nossas outras funções básicas de comparação, comoarrayEqual
earrayDeepEqual
etc.Na minha opinião, o melhor tipo de código nem precisa de comentários, e isso não é exceção. Há tão pouco acontecendo aqui que você pode entender o comportamento deste procedimento quase sem nenhum esforço. Claro, algumas das sintaxes do ES6 podem parecer estranhas para você agora, mas isso ocorre apenas porque o ES6 é relativamente novo.
Como o tipo sugere,
arrayCompare
assume a função de comparação,,f
e duas matrizes de entrada,xs
eys
. Na maior parte, tudo o que fazemos é chamarf (x) (y)
cada elemento nas matrizes de entrada. Retornamos cedofalse
se of
retorno definido pelo usuáriofalse
- graças à&&
avaliação de curto-circuito. Portanto, sim, isso significa que o comparador pode interromper a iteração antecipadamente e impedir o loop pelo restante da matriz de entrada quando desnecessário.Comparação estrita
Em seguida, usando nossa
arrayCompare
função, podemos criar facilmente outras funções que possamos precisar. Vamos começar com o elementararrayEqual
...Simples assim.
arrayEqual
pode ser definido comarrayCompare
e uma função comparadora que se comparaa
aob
uso===
(para igualdade estrita).Observe que também definimos
equal
como sua própria função. Isso destaca o papel dearrayCompare
uma função de ordem superior para utilizar nosso comparador de primeira ordem no contexto de outro tipo de dados (Matriz).Comparação fraca
Poderíamos ser facilmente definidos
arrayLooseEqual
usando um==
. Agora, ao comparar1
(Number) a'1'
(String), o resultado serátrue
…Comparação profunda (recursiva)
Você provavelmente já reparou que essa é apenas uma comparação superficial. Certamente a solução de Tomáš é "The Right Way ™" porque implica uma comparação profunda implícita, certo?
Bem, nosso
arrayCompare
procedimento é versátil o suficiente para ser usado de uma maneira que torna fácil um teste de igualdade profundo…Simples assim. Construímos um comparador profundo usando outra função de ordem superior. Desta vez, estamos encerrando
arrayCompare
usando um comparador personalizado que verificará sea
eb
são matrizes. NessearrayDeepCompare
caso , aplique novamente a comparaçãoa
eb
o comparador especificado pelo usuário (f
). Isso nos permite manter o profundo comportamento de comparação separado de como realmente comparamos os elementos individuais. Ou seja, como mostra o exemplo acima, podemos comparar profundamente usandoequal
,looseEqual
ou qualquer outra comparação que fazemos.Por
arrayDeepCompare
ser curry, podemos aplicá-lo parcialmente como fizemos nos exemplos anterioresPara mim, isso já é uma clara melhoria em relação à solução de Tomáš, porque eu posso escolher explicitamente uma comparação superficial ou profunda para minhas matrizes, conforme necessário.
Comparação de objetos (exemplo)
Agora, e se você tiver uma variedade de objetos ou algo assim? Talvez você queira considerar essas matrizes como "iguais" se cada objeto tiver o mesmo
id
valor ...Simples assim. Aqui eu usei objetos JS vanilla, mas esse tipo de comparador pode funcionar para qualquer tipo de objeto; até seus objetos personalizados. A solução de Tomáš precisaria ser completamente reformulada para suportar esse tipo de teste de igualdade
Matriz profunda com objetos? Não é um problema. Criamos funções genéricas altamente versáteis, para que funcionem em uma ampla variedade de casos de uso.
Comparação arbitrária (exemplo)
Ou, e se você quisesse fazer algum outro tipo de comparação completamente arbitrária? Talvez eu queira saber se cada um
x
é maior que cada umy
...Menos é mais
Você pode ver que estamos realmente fazendo mais com menos código. Não há nada de complicado em
arrayCompare
si e cada um dos comparadores personalizados que criamos tem uma implementação muito simples.Com facilidade, podemos definir exatamente como nós desejamos para duas matrizes para ser comparado - superficial, profunda, rigorosa, solto, alguma propriedade objeto, ou alguma computação arbitrária, ou qualquer combinação destes - todos usando um único procedimento ,
arrayCompare
. Talvez até sonhe com umRegExp
comparador! Eu sei como as crianças adoram esses regexps ...É o mais rápido? Não. Mas provavelmente também não precisa ser. Se a velocidade for a única métrica usada para medir a qualidade do nosso código, muitos códigos realmente ótimos serão descartados. É por isso que estou chamando essa abordagem de The Practical Way . Ou talvez para ser mais justo, uma maneira prática. Esta descrição é adequada para esta resposta porque não estou dizendo que esta resposta é apenas prática em comparação com alguma outra resposta; é objetivamente verdadeiro. Atingimos um alto grau de praticidade com muito pouco código e muito fácil de raciocinar. Nenhum outro código pode dizer que não recebemos essa descrição.
Isso faz com que seja a solução "certa" para você? Isso depende de você decidir. E ninguém mais pode fazer isso por você; só você sabe quais são suas necessidades. Em quase todos os casos, valorizo códigos simples, práticos e versáteis, em vez de tipos inteligentes e rápidos. O que você valoriza pode ser diferente, então escolha o que funciona melhor para você.
Editar
Minha resposta antiga estava mais focada em decompor-se
arrayEqual
em procedimentos minúsculos. É um exercício interessante, mas não é realmente a melhor (mais prática) maneira de abordar esse problema. Se você estiver interessado, poderá ver este histórico de revisões.fonte
arrayCompare
? Sim, a função é curry, mas difere desome
eevery
.arrayCompare
leva um comparador e duas matrizes para comparar. Eu escolhi um nome especificamente genérico porque podemos comparar matrizes usando qualquer função arbitrária. A função é curry para que possa ser especializada na criação de novas funções de comparação de array (por exemplo,arrayEqual
). Você pode sugerir um nome melhor? Em que áreas você acha que precisam de mais comentários ou explicações? Estou feliz em discutir ^ _ ^No espírito da pergunta original:
Fiz testes de desempenho em algumas das sugestões mais simples propostas aqui com os seguintes resultados (rápido a lento):
enquanto (67%) por Tim Down
cada (69%) por usuário2782196
reduzir (74%) por DEIs
juntar-se e toString (78%) por Gaizka Allende & vivek
metade toString (90%) de Victor Palomo
stringify (100%) por radtek
fonte
Array.from({length: 1000}).map((a,v)=>
$ {v}.padStart(10,2));
Com base na resposta de Tomáš Zato, concordo que apenas a iteração pelas matrizes é a mais rápida. Além disso (como outros já declararam), a função deve ser chamada igual / igual, não comparada. À luz disso, modifiquei a função para lidar com a comparação de matrizes por similaridade - ou seja, elas têm os mesmos elementos, mas fora de ordem - para uso pessoal, e pensei em colocá-la aqui para que todos possam ver.
Essa função usa um parâmetro adicional de strict que padroniza como true. Esse parâmetro estrito define se as matrizes precisam ser totalmente iguais no conteúdo e na ordem desses conteúdos, ou simplesmente contêm o mesmo conteúdo.
Exemplo:
Também escrevi um jsfiddle rápido com a função e este exemplo:
http://jsfiddle.net/Roundaround/DLkxX/
fonte
Mesmo que isso tenha muitas respostas, acredito que seja útil:
Não está indicado na pergunta como será a estrutura da matriz, portanto, se você tiver certeza de que não terá matrizes aninhadas nem objetos na matriz (aconteceu comigo, foi por isso que cheguei a isso). resposta) o código acima funcionará.
O que acontece é que usamos o operador spread (...) para concaturar as duas matrizes e usamos Set para eliminar quaisquer duplicatas. Depois de ter feito isso, você pode comparar seus tamanhos, se todas as três matrizes tiverem o mesmo tamanho, você estará pronto.
Essa resposta também ignora a ordem dos elementos , como eu disse, a situação exata aconteceu comigo, então talvez alguém na mesma situação possa acabar aqui (como eu).
Editar
Respondendo à pergunta de Dmitry Grinko: "Por que você usou o operador de spread (...) aqui - ... o novo conjunto? Ele não funciona"
Considere este código:
Você terá
Para trabalhar com esse valor, você precisará usar algumas propriedades do conjunto (consulte https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ). Por outro lado, quando você usa este código:
Você terá
Essa é a diferença, o primeiro me daria um conjunto, funcionaria também, pois eu poderia obter o tamanho desse conjunto, mas o último me forneceria o conjunto necessário, o que é mais direto para a resolução.
fonte
Nas mesmas linhas que JSON.encode é usar join ().
O único problema é se você se preocupa com os tipos testados pela última comparação. Se você se importa com os tipos, terá que fazer um loop.
Se a ordem permanecer a mesma, do que é apenas um loop, nenhuma classificação será necessária.
fonte
.join()
. Talvez se você declarasse sua segunda solução como principal (como a melhor, apesar de desdentada contra matrizes multidimensionais), eu não o julgaria dessa maneira. Até agora, reduzi todas as respostas que convertem matrizes em strings. Também votei em todos que usam da maneira certa, caso você precise saber disso. Isso significa a resposta de @Tim Down e a de Bireys.checkArrays([1,2,3] , ["1,2",3]) == true
e é muito improvável que é isso que você quer que aconteça!join()
desta maneira o torna sutilmente buggy!Aqui está uma versão datilografada:
Alguns casos de teste para mocha:
fonte
Se você estiver usando uma estrutura de teste como o Mocha com a biblioteca de asserções Chai , poderá usar profunda igualdade para comparar matrizes.
Isso deve retornar verdadeiro somente se as matrizes tiverem elementos iguais nos índices correspondentes.
fonte
Se são apenas duas matrizes de números ou cadeias, esta é uma rápida
fonte
[11]
. Bem óbvio por que isso acontece e como consertar.No meu caso, matrizes comparadas contêm apenas números e seqüências de caracteres. Esta função mostrará se as matrizes contêm os mesmos elementos.
Vamos testar!
fonte
are_arrs_equal([1,2], [2,1])
. Além disso, consulte outras discussões nesta página para saber por que a stringing é desnecessária, frágil e incorreta.are_arrs_equal([1,2], [2,1])
retornatrue
como esperado. Talvez essa solução não seja ideal, mas funcionou para mim.are_arrs_match([1,2], ["1,2"])
(retornatrue
). E observe que athe sort()
chamada modificará as matrizes de entrada - isso pode não ser desejável.Isso compara duas matrizes não classificadas:
fonte
Para uma matriz de números, tente:
Mostrar snippet de código
Nota: este método não funcionará quando a matriz também contiver cadeias, por exemplo
a2 = [1, "2,3"]
.fonte
Poderíamos fazer isso da maneira funcional, usando
every
( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every )fonte
Seu código não tratará o caso adequadamente quando as duas matrizes tiverem os mesmos elementos, mas não na mesma ordem.
Dê uma olhada no meu código com o seu exemplo, que compara duas matrizes cujos elementos são números. Você pode modificá-lo ou estendê-lo para outros tipos de elementos (utilizando .join () em vez de .toString ()).
fonte
Herer é minha solução:
Funciona com qualquer estrutura de dados aninhada e obviamente ignora os métodos dos objetos. Nem pense em estender Object.prototype com esse método, quando tentei isso uma vez, o jQuery quebrou;)
Para a maioria das matrizes, ainda é mais rápido que a maioria das soluções de serialização. É provavelmente o método de comparação mais rápido para matrizes de registros de objetos.
fonte
equal({}, {a:1})
eequal({}, null)
e este erros fora:equal({a:2}, null)
Foi assim que eu fiz.
fonte
Comparando 2 matrizes:
função de chamada
fonte
Eu acredito em pura
JS
e comECMAScript 2015
, o que é doce e simples de entender.espero que ajude alguém.
fonte
Ampliando a idéia de Tomáš Zato. O Array.prototype.compare de Tomas deve ser chamado de Array.prototype.compareIdentical.
Passa adiante:
Mas falha:
Aqui está a versão melhor (na minha opinião):
http://jsfiddle.net/igos/bcfCY/
fonte
////// OR ///////
fonte
Outra abordagem com muito pouco código (usando Array reduzir e Matriz inclui ):
Se você deseja comparar também a igualdade de ordem:
A
length
verificação garante que o conjunto de elementos em uma matriz não seja apenas um subconjunto da outra.O redutor é usado para percorrer uma matriz e procurar cada item em outra matriz. Se um item não for encontrado, a função reduzir retornará
false
.fonte
Uma abordagem simples:
fonte
Já tenho ótimas respostas. Mas eu gostaria de compartilhar uma outra idéia que provou ser confiável na comparação de matrizes. Podemos comparar duas matrizes usando JSON.stringify () . Ele criará uma string para fora do array e, assim, comparará duas strings obtidas de dois array para igualdade
fonte
Recursivo e funciona em matrizes NESTED :
fonte
Funciona com vários argumentos com matrizes NESTED :
fonte
fonte