Como comparar matrizes em JavaScript?

988

Eu gostaria de comparar duas matrizes ... idealmente, eficientemente. Nada extravagante, apenas truese eles são idênticos, e falsese 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?

Julian H. Lam
fonte
5
Você pode primeiro comparar o comprimento e se eles são iguais a cada valor.
TJHeuvel
55
O que torna duas matrizes iguais para você? Mesmos elementos? Mesma ordem de elementos? A codificação como JSON funciona apenas desde que o elemento da matriz possa ser serializado para JSON. Se a matriz puder conter objetos, qual a sua profundidade? Quando dois objetos são "iguais"?
Felix Kling
48
@FelixKling, definir "igualdade" é definitivamente um tópico sutil, mas para pessoas que acessam o JavaScript de idiomas de nível superior, não há desculpa para bobagens ([] == []) == false.
Alex D
4
@AlexD, parece que matrizes usam igualdade de referência, o que você esperaria. Seria horrível se você não poderia fazer isso
JonnyRaa
3
@ AlexD Eu não consigo pensar em um idioma em que isso não aconteça. Em C ++, você compararia dois ponteiros - false. Em Java, você está fazendo o mesmo que em javascript. No PHP, algo nos bastidores passará pelas matrizes - você chama o PHP de uma linguagem de nível superior?
Tomáš Zato - Restabelece Monica

Respostas:

877

Para comparar matrizes, faça um loop entre elas e compare todos os valores:

Comparando matrizes:

// Warn if overriding existing method
if(Array.prototype.equals)
    console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");
// attach the .equals method to Array's prototype to call it on any array
Array.prototype.equals = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time 
    if (this.length != array.length)
        return false;

    for (var i = 0, l=this.length; i < l; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].equals(array[i]))
                return false;       
        }           
        else if (this[i] != array[i]) { 
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;   
        }           
    }       
    return true;
}
// Hide method from for-in loops
Object.defineProperty(Array.prototype, "equals", {enumerable: false});

Uso:

[1, 2, [3, 4]].equals([1, 2, [3, 2]]) === false;
[1, "2,3"].equals([1, 2, 3]) === false;
[1, 2, [3, 4]].equals([1, 2, [3, 4]]) === true;
[1, 2, 1, 2].equals([1, 2, 1, 2]) === true;

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:

({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666})  //false

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:

Object.prototype.equals = function(object2) {
    //For the first loop, we only check for types
    for (propName in this) {
        //Check for inherited methods and properties - like .equals itself
        //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
        //Return false if the return value is different
        if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
            return false;
        }
        //Check instance type
        else if (typeof this[propName] != typeof object2[propName]) {
            //Different types => not equal
            return false;
        }
    }
    //Now a deeper check using other objects property names
    for(propName in object2) {
        //We must check instances anyway, there may be a property that only exists in object2
            //I wonder, if remembering the checked values from the first loop would be faster or not 
        if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
            return false;
        }
        else if (typeof this[propName] != typeof object2[propName]) {
            return false;
        }
        //If the property is inherited, do not check any more (it must be equa if both objects inherit it)
        if(!this.hasOwnProperty(propName))
          continue;

        //Now the detail check and recursion

        //This returns the script back to the array comparing
        /**REQUIRES Array.equals**/
        if (this[propName] instanceof Array && object2[propName] instanceof Array) {
                   // recurse into the nested arrays
           if (!this[propName].equals(object2[propName]))
                        return false;
        }
        else if (this[propName] instanceof Object && object2[propName] instanceof Object) {
                   // recurse into another objects
                   //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
           if (!this[propName].equals(object2[propName]))
                        return false;
        }
        //Normal value comparison for strings and numbers
        else if(this[propName] != object2[propName]) {
           return false;
        }
    }
    //If everything passed, let's say YES
    return true;
}  

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.equalsvocê deve editar um pouco a função original:

...
    // Check if we have nested arrays
    if (this[i] instanceof Array && array[i] instanceof Array) {
        // recurse into the nested arrays
        if (!this[i].equals(array[i]))
            return false;
    }
    /**REQUIRES OBJECT COMPARE**/
    else if (this[i] instanceof Object && array[i] instanceof Object) {
        // recurse into another objects
        //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
        if (!this[i].equals(array[i]))
            return false;
        }
    else if (this[i] != array[i]) {
...

Fiz uma pequena ferramenta de teste para ambas as funções .

Bônus: matrizes aninhadas com indexOfecontains

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/

Tomáš Zato - Restabelecer Monica
fonte
27
Se você quiser fazer comparações estritas, use em this[i] !== array[i]vez de !=.
Tim S.
38
Seu método deve ser chamado em equalsvez de compare. Pelo menos no .NET, compare geralmente retorna um int assinado indicando qual objeto é maior que o outro. Consulte: Comparer.Compare .
314 Oliver
15
Nt é apenas o modo certo de fazê-lo, também é consideravelmente mais eficaz. Aqui está um rápido script jsperf que eu preparei para todos os métodos sugeridos nesta pergunta. jsperf.com/comparing-arrays2
Tolga E
96
Mudando um built-in protótipo do tipo não é definitivamente o caminho certo
Jasper
31
Além disso, não é fácil reescrever, é sobre o fato de que uma resposta não deve recomendar algo que é considerado uma má prática ( developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/… ) e deve definitivamente não faça isso abaixo do cabeçalho "O caminho certo"
Jasper
386

Embora isso funcione apenas para matrizes escalares (veja a nota abaixo), é curto:

array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})

Rr, no ECMAScript 6 / CoffeeScript / TypeScript com funções de seta:

array1.length === array2.length && array1.every((value, index) => value === array2[index])

(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:

array1.length === array2.length && array1.sort().every(function(value, index) { return value === array2.sort()[index]});

Por exemplo:

array1 = [2,3,1,4];
array2 = [1,2,3,4];

Então o código acima daria true

user2782196
fonte
19
Eu gosto disso, embora os leitores devam estar cientes de que isso só funciona em matrizes classificadas.
Ellen Spertus
13
Ele funciona em qualquer tipo de matrizes, classificado ou não @espertus
Michał Miszczyszyn
36
Sim, exatamente. Essa função deve comparar duas matrizes, não importa se elas estão classificadas ou não, seus elementos consecutivos devem ser iguais.
Michał Miszczyszyn 26/03
22
@espertus De fato, ele não retornará true se os elementos não tiverem exatamente a mesma ordem nas duas matrizes. No entanto, o objetivo de uma verificação de igualdade não é verificar se eles contêm os mesmos elementos, mas verificar se eles têm o mesmo elemento nas mesmas ordens.
Quentin Roy
7
Se você quiser verificar se ambas as matrizes são iguais, contendo os mesmos itens indiferenciados (mas não utilizados várias vezes), você pode usar 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)
MEMS
208

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:

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean
Jason Boerner
fonte
22
Note-se que as questões de ordem _.isEqual([1,2,3], [2,1,3]) => false
Vitaliy Alekask
3
ou se você quiser apenas a isEqualfuncionalidade, sempre poderá usar o módulo
lodash.isequal #
6
Talvez você possa usar _.difference (); se a ordem não importa para você
Ronan Quillevere
5
Podemos classificar a matriz antes dessa verificação se a ordem não importa _.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Filype
resposta mais concisa e direta IMHO :-)
Kieran Ryan
121

Acho que é a maneira mais simples de fazer isso usando JSON stringify, e pode ser a melhor solução em algumas situações:

JSON.stringify(a1) === JSON.stringify(a2);

Isso converte os objetos a1e a2em 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.

Radtek
fonte
boa resposta, mas por que [] == [] retorna falso? ambos são objetos simples, então por quê?
precisa saber é o seguinte
4
@PardeepJain, isso ocorre porque, por padrão, o operador de igualdade no ECMAScript for Objects retorna true quando eles fazem referência ao mesmo local de memória. Tente var x = y = []; // agora igualdade retorna true.
Radtek
7
apenas observe que a função JSON stringify não é rápida. Usado com matrizes maiores definitivamente introduzirá lag.
Lukas Liesis
6
A pergunta pergunta especificamente se existe uma maneira melhor / mais rápida do que usar o JSON.stringify.
Don Hatch
Ele entra em mais detalhes sobre por que essa pode ser uma boa solução para algumas situações.
Radtek
61

Não está claro o que você quer dizer com "idêntico". Por exemplo, as matrizes ae babaixo são idênticas (observe as matrizes aninhadas)?

var a = ["foo", ["bar"]], b = ["foo", ["bar"]];

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)retornaria false. Funciona no caso geral, que as join()soluções baseadas em JSON e não:

function arraysIdentical(a, b) {
    var i = a.length;
    if (i != b.length) return false;
    while (i--) {
        if (a[i] !== b[i]) return false;
    }
    return true;
};
Tim Down
fonte
@ ASDF: Não está claro na pergunta o que "idêntico" significa. Obviamente, essa resposta faz apenas uma verificação superficial. Vou adicionar uma nota.
Tim Baixo
isso falha para arraysIdentical ([1, 2, [3, 2]], [1, 2, [3, 2]]);
Gopinath Shiva
4
@GopinathShiva: Bem, só falha se você espera que ele volte true. A resposta explica que não. Se você precisar comparar matrizes aninhadas, poderá adicionar facilmente uma verificação recursiva.
Tim Down
59

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 arrayCompareprocedimento genérico que se preocupa apenas em percorrer as matrizes. A partir daí, criaremos nossas outras funções básicas de comparação, como arrayEquale arrayDeepEqualetc.

// arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayCompare = f => ([x,...xs]) => ([y,...ys]) =>
  x === undefined && y === undefined
    ? true
    : Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys)

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, arrayCompareassume a função de comparação,, fe duas matrizes de entrada, xse ys. Na maior parte, tudo o que fazemos é chamar f (x) (y)cada elemento nas matrizes de entrada. Retornamos cedo falsese o fretorno definido pelo usuário false- 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 arrayComparefunção, podemos criar facilmente outras funções que possamos precisar. Vamos começar com o elementar arrayEqual...

// equal :: a -> a -> Bool
const equal = x => y =>
  x === y // notice: triple equal

// arrayEqual :: [a] -> [a] -> Bool
const arrayEqual =
  arrayCompare (equal)

const xs = [1,2,3]
const ys = [1,2,3]
console.log (arrayEqual (xs) (ys))      //=> true
// (1 === 1) && (2 === 2) && (3 === 3)  //=> true

const zs = ['1','2','3']
console.log (arrayEqual (xs) (zs))      //=> false
// (1 === '1')                          //=> false

Simples assim. arrayEqualpode ser definido com arrayComparee uma função comparadora que se compara aao buso=== (para igualdade estrita).

Observe que também definimos equalcomo sua própria função. Isso destaca o papel de arrayCompareuma 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 arrayLooseEqualusando um ==. Agora, ao comparar 1(Number) a '1'(String), o resultado será true

// looseEqual :: a -> a -> Bool
const looseEqual = x => y =>
  x == y // notice: double equal

// arrayLooseEqual :: [a] -> [a] -> Bool
const arrayLooseEqual =
  arrayCompare (looseEqual)

const xs = [1,2,3]
const ys = ['1','2','3']
console.log (arrayLooseEqual (xs) (ys))    //=> true
// (1 == '1') && (2 == '2') && (3 == '3')  //=> 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 arrayCompareprocedimento é versátil o suficiente para ser usado de uma maneira que torna fácil um teste de igualdade profundo…

// isArray :: a -> Bool
const isArray =
  Array.isArray

// arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayDeepCompare = f =>
  arrayCompare (a => b =>
    isArray (a) && isArray (b)
      ? arrayDeepCompare (f) (a) (b)
      : f (a) (b))

const xs = [1,[2,[3]]]
const ys = [1,[2,['3']]]
console.log (arrayDeepCompare (equal) (xs) (ys)) //=> false
// (1 === 1) && (2 === 2) && (3 === '3')         //=> false

console.log (arrayDeepCompare (looseEqual) (xs) (ys)) //=> true
// (1 == 1) && (2 == 2) && (3 == '3')                 //=> true

Simples assim. Construímos um comparador profundo usando outra função de ordem superior. Desta vez, estamos encerrando arrayCompareusando um comparador personalizado que verificará se ae bsão matrizes. Nesse arrayDeepComparecaso , aplique novamente a comparação ae bo 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 usando equal,looseEqual ou qualquer outra comparação que fazemos.

Por arrayDeepCompareser curry, podemos aplicá-lo parcialmente como fizemos nos exemplos anteriores

// arrayDeepEqual :: [a] -> [a] -> Bool
const arrayDeepEqual =
  arrayDeepCompare (equal)

// arrayDeepLooseEqual :: [a] -> [a] -> Bool
const arrayDeepLooseEqual =
  arrayDeepCompare (looseEqual)

Para 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 idvalor ...

// idEqual :: {id: Number} -> {id: Number} -> Bool
const idEqual = x => y =>
  x.id !== undefined && x.id === y.id

// arrayIdEqual :: [a] -> [a] -> Bool
const arrayIdEqual =
  arrayCompare (idEqual)

const xs = [{id:1}, {id:2}]
const ys = [{id:1}, {id:2}]
console.log (arrayIdEqual (xs) (ys)) //=> true
// (1 === 1) && (2 === 2)            //=> true

const zs = [{id:1}, {id:6}]
console.log (arrayIdEqual (xs) (zs)) //=> false
// (1 === 1) && (2 === 6)            //=> false

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.

const xs = [{id:1}, [{id:2}]]
const ys = [{id:1}, [{id:2}]]
console.log (arrayCompare (idEqual) (xs) (ys))     //=> false
console.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true

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 um y...

// gt :: Number -> Number -> Bool
const gt = x => y =>
  x > y

// arrayGt :: [a] -> [a] -> Bool
const arrayGt = arrayCompare (gt)

const xs = [5,10,20]
const ys = [2,4,8]
console.log (arrayGt (xs) (ys))     //=> true
// (5 > 2) && (10 > 4) && (20 > 8)  //=> true

const zs = [6,12,24]
console.log (arrayGt (xs) (zs))     //=> false
// (5 > 6)                          //=> false

Menos é mais

Você pode ver que estamos realmente fazendo mais com menos código. Não há nada de complicado em arrayComparesi 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 um RegExpcomparador! 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 arrayEqualem 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.

Obrigado
fonte
8
"o melhor tipo de código nem precisa de comentários" ... detesto dizer isso, mas esse código pode usar mais comentários e / ou um nome diferente - "comparar" é bastante vago. Se estou lendo corretamente, sua "comparação" é essencialmente um "cada" recursivo ao curry. Eu acho que. Ou é um "alguns" recursivos ao curry? Hmm. Isso requer mais pensamento do que o necessário. Talvez um nome melhor seja "arraysEquivalent", aproveitando a terminologia padrão da "relação de equivalência". Ou, ainda mais claro (para mim de qualquer maneira), "recursivelyEquivalent".
Don Hatch
1
@ DonHatch obrigado pela oportunidade de responder. Com "comparar" você quer dizer arrayCompare? Sim, a função é curry, mas difere de somee every. arrayCompareleva 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 ^ _ ^
Obrigado
1
Ainda não tenho certeza se meu argumento está claro - mas o que quero dizer é que sua função não tem a intenção de assumir uma função arbitrária , eu acho - ela tem uma relação de equivalência e retorna uma relação de equivalência. Isso é importante - não faria nada sensato (eu não acho) se recebesse algum outro tipo de função binária arbitrária como as que eu mencionei, mesmo aquelas que as pessoas costumam chamar de "comparar". Então eu acho que seria útil colocar "equivalente" no nome no lugar de "comparar".
Don Hatch
1
@ftor, autor: resposta super útil, bom trabalho, +1. Feedback: você defende a simplicidade, mas de nenhuma maneira é uma expressão com três setas em uma linha simples ou fácil de entender para muitos desenvolvedores. Por exemplo: f => ([x, ... xs]) => ([y, ... ys]) =>. Eu constantemente uso isso e ainda tenho que decompor mentalmente, em vez de "apenas olhar". O segundo ponto é certo, use todos. Mesmo ponderando suas razões, no geral, parece melhor não apenas para mim, mas também da sua perspectiva, quando tenta inferir sua filosofia de design.
whitneyland
1
Entendo que este é um lugar para aprender, mas suponho aqui que o programador médio que estuda estilo funcional possa transformar qualquer função com curry em uma função sem cursar. Minha resposta não sugere que esse estilo seja usado em seu próprio programa - escreva-o sem pressa, escreva-o usando suas próprias regras de indentação, escreva como quiser - escrevo minhas respostas em um estilo que, acredito, expressa o programa melhor. Também gosto de convidar outras pessoas a desafiar a maneira como expressamos nossos programas de forma sintática
Obrigado
54

No espírito da pergunta original:

Eu gostaria de comparar duas matrizes ... idealmente, eficientemente . Nada extravagante , apenas verdadeiro se eles são idênticos e falso se não.

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

var i = a1.length;
while (i--) {
    if (a1[i] !== a2[i]) return false;
}
return true

cada (69%) por usuário2782196

a1.every((v,i)=> v === a2[i]);

reduzir (74%) por DEIs

a1.reduce((a, b) => a && a2.includes(b), true);

juntar-se e toString (78%) por Gaizka Allende & vivek

a1.join('') === a2.join('');

a1.toString() === a2.toString();

metade toString (90%) de Victor Palomo

a1 == a2.toString();

stringify (100%) por radtek

JSON.stringify(a1) === JSON.stringify(a2);

Observe que os exemplos abaixo assumem que as matrizes são classificadas e matrizes unidimensionais. .lengtha comparação foi removida para uma referência comum (adicione a1.length === a2.lengtha qualquer uma das sugestões e você obterá um aumento de ~ 10% no desempenho). Escolha as soluções que funcionem melhor para você conhecer a velocidade e as limitações de cada uma.

Nota não relacionada: é interessante ver as pessoas recebendo John Waynes, que está feliz no gatilho, no botão de votação para baixo, em respostas perfeitamente legítimas a esta pergunta.

unitario
fonte
O link abre um teste vazio.
Alexander Abakumov
Se você aumentar o tamanho da matriz, esses números não se aplicarão (especialmente a abordagem de redução). Tente com Array.from({length: 1000}).map((a,v)=> $ {v}.padStart(10,2));
Narayon 27/08/19
ele só funciona para matriz rasa
Ramesh Rajendran
28

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.

Array.prototype.equals = function (array, strict) {
    if (!array)
        return false;

    if (arguments.length == 1)
        strict = true;

    if (this.length != array.length)
        return false;

    for (var i = 0; i < this.length; i++) {
        if (this[i] instanceof Array && array[i] instanceof Array) {
            if (!this[i].equals(array[i], strict))
                return false;
        }
        else if (strict && this[i] != array[i]) {
            return false;
        }
        else if (!strict) {
            return this.sort().equals(array.sort(), true);
        }
    }
    return true;
}

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:

var arr1 = [1, 2, 3, 4];
var arr2 = [2, 1, 4, 3];  // Loosely equal to 1
var arr3 = [2, 2, 3, 4];  // Not equal to 1
var arr4 = [1, 2, 3, 4];  // Strictly equal to 1

arr1.equals(arr2);         // false
arr1.equals(arr2, false);  // true
arr1.equals(arr3);         // false
arr1.equals(arr3, false);  // false
arr1.equals(arr4);         // true
arr1.equals(arr4, false);  // true

Também escrevi um jsfiddle rápido com a função e este exemplo:
http://jsfiddle.net/Roundaround/DLkxX/

Evan Steinkerchner
fonte
12

Mesmo que isso tenha muitas respostas, acredito que seja útil:

const newArray = [ ...new Set( [...arr1, ...arr2] ) ]

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:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Você terá

[ Set { 'a', 'b', 'c' } ]

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:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Você terá

[ 'a', 'b', 'c' ]

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.

Jeferson Euclides
fonte
Por que você usou o operador de propagação (...) aqui - ... novo conjunto? Isso não funciona.
Dmitry Grinko
Dmitry Grinko Acredito que respondi sua pergunta no meu Edit1. Mas eu não tenho certeza que você entende por dizer 'não funciona', como ambas as respostas que você pode obter no caminho
Jeferson Euclides
10

Nas mesmas linhas que JSON.encode é usar join ().

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    //slice so we do not effect the original
    //sort makes sure they are in order
    //join makes it a string so we can do a string compare
    var cA = arrA.slice().sort().join(","); 
    var cB = arrB.slice().sort().join(",");

    return cA===cB;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];  //will return true

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //true

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.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;

    //slice so we do not effect the orginal
    //sort makes sure they are in order
    var cA = arrA.slice().sort(); 
    var cB = arrB.slice().sort();

    for(var i=0;i<cA.length;i++){
         if(cA[i]!==cB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false

Se a ordem permanecer a mesma, do que é apenas um loop, nenhuma classificação será necessária.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    for(var i=0;i<arrA.length;i++){
         if(arrA[i]!==arrB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,a) );  //true
console.log( checkArrays(a,b) );  //false
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false
epascarello
fonte
3
Isso funciona apenas para determinadas matrizes e será muito lento com grandes matrizes.
Tomáš Zato - Restabelecer Monica
2
A geração de JSON também está em loop, você apenas (ou parece) não sabe disso. Além de fazer um loop, a geração de JSON também requer mais memória - ele cria duas representações de string das referidas matrizes antes de comparar. A função downwote é implementada para solicitar respostas do melhor para o pior. Eu acho que sua resposta não é uma boa resposta, então eu a diminuí.
Tomáš Zato - Restabelece Monica
2
Desculpe, eu apenas disse JSON em vez de .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.
Tomáš Zato - Restabelecer Monica
6
Primeira versão FAILS:, checkArrays([1,2,3] , ["1,2",3]) == truee é muito improvável que é isso que você quer que aconteça!
Doin
2
@epascarello: Sim, você pode, mas (além da ineficiência do separador muito longo que você sugere), isso significa que haverá casos de borda (onde o array contém uma string com o seu separador) onde a função checkArrays () se comporta mal . Isso pode não ser um problema se você souber algo sobre o conteúdo das matrizes (para poder escolher um separador com certeza não estará nos itens da matriz), mas se estiver tentando escrever uma comparação geral de matrizes função, então usar join()desta maneira o torna sutilmente buggy!
Doin
7

Aqui está uma versão datilografada:

//https://stackoverflow.com/a/16436975/2589276
export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean {
    if (a === b) return true
    if (a == null || b == null) return false
    if (a.length != b.length) return false

    for (var i = 0; i < a.length; ++i) {
        if (a[i] !== b[i]) return false
    }
    return true
}

//https://stackoverflow.com/a/16436975/2589276
export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {
    return JSON.stringify(a) === JSON.stringify(b)
}

Alguns casos de teste para mocha:

it('arraysEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']

    expect(arraysEqual(a, b)).to.equal(true)
    expect(arraysEqual(c, d)).to.equal(true)
    expect(arraysEqual(a, d)).to.equal(false)
    expect(arraysEqual(e, f)).to.equal(true)
    expect(arraysEqual(f, g)).to.equal(false)
})

it('arraysDeepEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']
    let h = [[1,2],'apple','banan8']
    let i = [[1,2],'apple','banan8']
    let j = [[1,3],'apple','banan8']

    expect(arraysDeepEqual(a, b)).to.equal(true)
    expect(arraysDeepEqual(c, d)).to.equal(true)
    expect(arraysDeepEqual(a, d)).to.equal(false)
    expect(arraysDeepEqual(e, f)).to.equal(true)
    expect(arraysDeepEqual(f, g)).to.equal(false)
    expect(arraysDeepEqual(h, i)).to.equal(true)
    expect(arraysDeepEqual(h, j)).to.equal(false)
})
Esqarrouth
fonte
6

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.

expect(a1).to.deep.equal(a2)

Isso deve retornar verdadeiro somente se as matrizes tiverem elementos iguais nos índices correspondentes.

metakermit
fonte
6

Se são apenas duas matrizes de números ou cadeias, esta é uma rápida

const array1 = [1, 2, 3];
const array2 = [1, 3, 4];
console.log(array1.join(',') === array2.join(',')) //false

const array3 = [1, 2, 3];
const array4 = [1, 2, 3];
console.log(array3.join(',') === array4.join(',')) //true
Gaizka Allende
fonte
const array1 = [1]; const array2 = [1, 1]; console.log (array1.join ('') === array2.join ('')) // retorna verdadeiro
Dan M.
não deveria: array1.join ('') é '1' e array2.join ('') é '11'
Gaizka Allende
desculpe, erro de digitação. A primeira matriz deve ser [11]. Bem óbvio por que isso acontece e como consertar.
Dan M.
Não tendo certeza do que você trata, é bem simples: [1] .join () é "1" e [1,1] .join () é "1,1", portanto eles nunca serão iguais
Gaizka Allende
por favor, leia meu comentário novamente com mais cuidado. Se você ainda não o vê, faça um saque em ideone.com/KFu427
Dan M.
5

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.

function are_arrs_match(arr1, arr2){
    return arr1.sort().toString() === arr2.sort().toString()
}

Vamos testar!

arr1 = [1, 2, 3, 'nik']
arr2 = ['nik', 3, 1, 2]
arr3 = [1, 2, 5]

console.log (are_arrs_match(arr1, arr2)) //true
console.log (are_arrs_match(arr1, arr3)) //false
yesnik
fonte
A pergunta não pede que você classifique, portanto, sua solução está errada para exemplos como 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.
tratar os seus mods bem
are_arrs_equal([1,2], [2,1])retorna truecomo esperado. Talvez essa solução não seja ideal, mas funcionou para mim.
yesnik 8/08/16
Esse é precisamente o problema: esses dois não são iguais em nenhum sentido sensato da palavra "igual" para uma estrutura de dados ordenada . Eles são matrizes, não conjuntos, e se você deseja definir igualdade, deve chamá-lo assim - e responder a uma pergunta diferente. :-)
tratar os seus mods bem
1
Eu concordo com os comentários acima, mas esta solução também funciona para mim em minhas matrizes simples de números inteiros, onde a ordem não é importante, então eu a usarei.
tomazahlin
1
Falha em are_arrs_match([1,2], ["1,2"])(retorna true). E observe que a the sort()chamada modificará as matrizes de entrada - isso pode não ser desejável.
try-catch-finalmente
5

Isso compara duas matrizes não classificadas:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}
Nathan Boolean Trujillo
fonte
Embora seja cara (em termos de recursos de computação), esta é uma solução robusta que deve ser boa para vários tipos e não depende da classificação!
User3.1415927 6/02
5

Para uma matriz de números, tente:

a1==''+a2

Nota: este método não funcionará quando a matriz também contiver cadeias, por exemplo a2 = [1, "2,3"].

Kamil Kiełczewski
fonte
truque inteligente ..
javadba 03/06
4

Poderíamos fazer isso da maneira funcional, usando every( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every )

function compareArrays(array1, array2) {
    if (array1.length === array2.length)
        return array1.every((a, index) => a === array2[index])
    else
        return false
}

// test
var a1 = [1,2,3];
var a2 = [1,2,3];

var a3 = ['a', 'r', 'r', 'a', 'y', '1']
var a4 = ['a', 'r', 'r', 'a', 'y', '2']

console.log(compareArrays(a1,a2)) // true
console.log(compareArrays(a1,a3)) // false
console.log(compareArrays(a3,a4)) // false
peonicles
fonte
4

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 ()).

var a1 = [1,2,3];
var a2 = [1,2,3];
const arraysAreEqual = a1.sort().toString()==a2.sort().toString();
// true if both arrays have same elements else false
console.log(arraysAreEqual);

durga patra
fonte
3

Herer é minha solução:

/**
 * Tests two data structures for equality
 * @param {object} x
 * @param {object} y
 * @returns {boolean}
 */
var equal = function(x, y) {
    if (typeof x !== typeof y) return false;
    if (x instanceof Array && y instanceof Array && x.length !== y.length) return false;
    if (typeof x === 'object') {
        for (var p in x) if (x.hasOwnProperty(p)) {
            if (typeof x[p] === 'function' && typeof y[p] === 'function') continue;
            if (x[p] instanceof Array && y[p] instanceof Array && x[p].length !== y[p].length) return false;
            if (typeof x[p] !== typeof y[p]) return false;
            if (typeof x[p] === 'object' && typeof y[p] === 'object') { if (!equal(x[p], y[p])) return false; } else
            if (x[p] !== y[p]) return false;
        }
    } else return x === y;
    return true;
};

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.

atormentar
fonte
nada de bom! estes dão verdadeira: equal({}, {a:1})e equal({}, null)e este erros fora:equal({a:2}, null)
kristianlm
3
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

Foi assim que eu fiz.

Leed
fonte
Boa solução - mas em algumas situações me pergunto se isso nem sempre funcionará como pretendido, como com certas primitivas ou matrizes profundamente aninhadas? Espero que funcione em todas as circunstâncias embora
Ben Rondeau
3

Comparando 2 matrizes:

var arr1 = [1,2,3];
var arr2 = [1,2,3];

function compare(arr1,arr2)
{
  if((arr1 == arr2) && (arr1.length == arr2.length))
    return true;
  else
    return false;
}

função de chamada

var isBool = compare(arr1.sort().join(),arr2.sort().join());
Amay Kulkarni
fonte
Essa resposta não funcionará, pois o === não se comporta conforme o esperado para matrizes.
Michael Yang
A resposta funciona, embora === não tenha nenhum significado aqui (uma vez que sort () funciona apenas na matriz). Par == também funcionará.
Amay Kulkarni
Experimente você mesmo; ele imprime false se você executar esse código. Isso ocorre devido à comparação dos valores de referência das matrizes por ambos == e === em vez de seus valores reais. Os == e === destinam-se apenas à comparação de tipos primitivos.
Michael Yang
Ele retorna verdade, nós tê-lo usado, mas eu removi '===' agora, pois não é necassary
Amay Kulkarni
Ah, eu não percebi que você estava convertendo em uma string e chamando a função após classificar e ingressar; Minhas desculpas.
Michael Yang
3

Eu acredito em pura JSe com ECMAScript 2015, o que é doce e simples de entender.

var is_arrays_compare_similar = function (array1, array2) {

    let flag = true;

    if (array1.length == array2.length) {

        // check first array1 object is available in array2 index
        array1.every( array_obj => {
            if (flag) {
                if (!array2.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        // then vice versa check array2 object is available in array1 index
        array2.every( array_obj => {
            if (flag) {
                if (!array1.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        return flag;
    } else {
        return false;
    }

}

espero que ajude alguém.

ArifMustafa
fonte
1
Por que a verificação vice-versa é necessária? Sabemos que as matrizes são do mesmo tamanho; portanto, se todos os itens da matriz1 também forem encontrados na matriz2; por que teríamos que verificar se todos os itens da matriz2 também estão na matriz1?
JeffryHouser
2

Ampliando a idéia de Tomáš Zato. O Array.prototype.compare de Tomas deve ser chamado de Array.prototype.compareIdentical.

Passa adiante:

[1, 2, [3, 4]].compareIdentical ([1, 2, [3, 2]]) === false;
[1, "2,3"].compareIdentical ([1, 2, 3]) === false;
[1, 2, [3, 4]].compareIdentical ([1, 2, [3, 4]]) === true;
[1, 2, 1, 2].compareIdentical ([1, 2, 1, 2]) === true;

Mas falha:

[[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]])

Aqui está a versão melhor (na minha opinião):

Array.prototype.compare = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time
    if (this.length != array.length)
        return false;

    this.sort();
    array.sort();
    for (var i = 0; i < this.length; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].compare(array[i]))
                return false;
        }
        else if (this[i] != array[i]) {
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;
        }
    }
    return true;
}

http://jsfiddle.net/igos/bcfCY/

Igor S.
fonte
2
-1. Se 'falhar' no exemplo que você deu, esse é apenas o caso de uma definição um tanto arbitrária de 'falha'. Por que você espera que essas duas matrizes diferentes sejam consideradas iguais? Você nem mesmo explicou que conceito de 'igualdade' você está tentando implementar aqui, ou por que é sensato ou útil, mas parece que você deseja que matrizes multidimensionais sejam comparadas como se fossem reduzidas para unidimensionais uns. Nesse caso, você nem conseguiu isso: [1,2] .compare ([[1,2]]) dá false com sua versão, assim como com Tomáš.
Mark Amery
Com base no que pude inferir, ele está dizendo que [1, 2, 3, 4] e [1, 3, 2, 4] devem ser comparados como iguais (ordem não importa).
Gautham Badhrinathan
2
var a1 = [1,2,3,6];
var a2 = [1,2,3,5];

function check(a, b) {
  return (a.length != b.length) ? false : 
  a.every(function(row, index) {
    return a[index] == b[index];
  });
}  

check(a1, a2);

////// OR ///////

var a1 = [1,2,3,6];
var a2 = [1,2,3,6];

function check(a, b) {
  return (a.length != b.length) ? false : 
  !(a.some(function(row, index) {
    return a[index] != b[index];
  }));
}  

check(a1, a2)
Vasanth
fonte
Você pode você alguma função bem que não irá iterar completamente se obter a condição exigida satisfeito, como acima
Vasanth
2

Outra abordagem com muito pouco código (usando Array reduzir e Matriz inclui ):

arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true)

Se você deseja comparar também a igualdade de ordem:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • A lengthverificaçã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.

    1. No primeiro exemplo, está sendo testado que um elemento está incluído
    2. O segundo exemplo também verifica o pedido
DEls
fonte
1
você poderia explicar um pouco o seu código para tornar essa resposta mais clara?
ted
1. compare os comprimentos da matriz para garantir que uma matriz não seja um subconjunto da outra
DEls 9/16
2. use o redutor para percorrer uma matriz e procurar cada item em outra matriz. Se um item não for encontrado, a função de redução retornará 'false'
DEls 09/11/16
@DEls: editou sua explicação na resposta (ligeiramente reformulada e ampliada). Agora você pode remover seus comentários e sinalizar o primeiro comentário e este como obsoleto.
try-catch-finalmente
2

Uma abordagem simples:

function equals(a, b) {
    if ((a && !b) || (!a && b) || (!a && !b) || (a.length !== b.length)) {
        return false;
    }

    var isDifferent = a.some(function (element, index) { 
        return element !== b[index];
    });

    return !isDifferent;
}
Pedro Rodrigues
fonte
2

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

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:1},2]) //true

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},2]) //false

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:1},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //true

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[4]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[5]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //true
AL-zami
fonte
2

Recursivo e funciona em matrizes NESTED :

function ArrEQ(a1,a2){
   return( 
        //:Are both elements arrays?
        Array.isArray(a1)&&Array.isArray(a2) 
        ?
        //:Yes: Test each entry for equality:
        a1.every((v,i)=>(ArrEQ(v,a2[i])))
        :
        //:No: Simple Comparison:
        (a1===a2)
   );;
};;

console.log( "Works With Nested Arrays:" );
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]],
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]]
));;     
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"DIFFERENT:APPLES" ]]],
    [1,2,3,[4,5,[6,"DIFFERENT:ORANGES"]]]
));;  
JMI MADISON
fonte
2

Funciona com vários argumentos com matrizes NESTED :

//:Return true if all of the arrays equal.
//:Works with nested arrays.
function AllArrEQ(...arrays){
    for(var i = 0; i < (arrays.length-1); i++ ){
        var a1 = arrays[i+0];
        var a2 = arrays[i+1];
        var res =( 
            //:Are both elements arrays?
            Array.isArray(a1)&&Array.isArray(a2) 
            ?
            //:Yes: Compare Each Sub-Array:
            //:v==a1[i]
            a1.every((v,i)=>(AllArrEQ(v,a2[i])))
            :
            //:No: Simple Comparison:
            (a1===a2)
        );;
        if(!res){return false;}
    };;
    return( true );
};;

console.log( AllArrEQ( 
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
));; 
JMI MADISON
fonte
2
In a simple way uning stringify but at same time thinking in complex arrays:

**Simple arrays**:  
var a = [1,2,3,4];  
var b = [4,2,1,4];  
JSON.stringify(a.sort()) === JSON.stringify(b.sort()) // true  

**Complex arrays**:  
var a = [{id:5,name:'as'},{id:2,name:'bes'}];  
var b = [{id:2,name:'bes'},{id:5,name:'as'}];  
JSON.stringify(a.sort(function(a,b) {return a.id - b.id})) === JSON.stringify(b.sort(function(a,b) {return a.id - b.id})) // true  

**Or we can create a sort function**  

function sortX(a,b) {  
return a.id -b.id; //change for the necessary rules  
}  
JSON.stringify(a.sort(sortX)) === JSON.stringify(b.sort(sortX)) // true  
Pedro Bustamante
fonte