Como saber se dois arrays têm os mesmos valores

104

Eu tenho esses dois arrays: um é preenchido com informações de uma solicitação ajax e outro armazena os botões em que o usuário clica. Eu uso este código (preenchi com números de amostra):

var array1 = [2, 4];
var array2 = [4, 2]; //It cames from the user button clicks, so it might be disordered.
array1.sort(); //Sorts both Ajax and user info.
array2.sort();
if (array1==array2) {
    doSomething();
}else{
    doAnotherThing();
}

Mas sempre dá false, mesmo que as duas matrizes sejam iguais, mas com nomes diferentes. (Eu verifiquei isso no console JS do Chrome). Então, há alguma maneira de eu saber se esses dois arrays contêm o mesmo? Por que está dando false? Como posso saber quais valores no primeiro array não estão no segundo?

Carlos precioso
fonte
1
Tenho certeza de que você precisa passar por cada elemento dos arrays.
Thomas Li
Você sabe por que retorna falso? Curioso.
RobW 01 de
Veja a resposta de @Andrew stackoverflow.com/a/6229263/702565
Carlos Precioso
possível duplicata de como verificar o array javascript é igual?
Palec

Respostas:

36
function arraysEqual(_arr1, _arr2) {

    if (!Array.isArray(_arr1) || ! Array.isArray(_arr2) || _arr1.length !== _arr2.length)
      return false;

    var arr1 = _arr1.concat().sort();
    var arr2 = _arr2.concat().sort();

    for (var i = 0; i < arr1.length; i++) {

        if (arr1[i] !== arr2[i])
            return false;

    }

    return true;

}

Observe que isso não modifica os arrays originais, ao contrário da resposta anterior.

Maciej Krawczyk
fonte
2
a classificação leva tempo nlog (n). Você não precisa de classificação. Esta resposta stackoverflow.com/a/55614659/3209523 funciona em tempo linear.
canbax de
O uso do typescript Array.isArray () estava causando erros, removendo que funcionava bem.
Ariel Frischer
88

Se seus itens de array não são objetos - se eles são números ou strings, por exemplo, você pode comparar suas strings unidas para ver se eles têm os mesmos membros em qualquer ordem -

var array1= [10, 6, 19, 16, 14, 15, 2, 9, 5, 3, 4, 13, 8, 7, 1, 12, 18, 11, 20, 17];
var array2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];

if(array1.sort().join(',')=== array2.sort().join(',')){
    alert('same members');
}
else alert('not a match');
kennebec
fonte
2
Isso funcionará bem para primitivos ou objetos que possuem valores toString de identificação exclusiva, mas não para qualquer objeto.
devios1
Obrigado! solução legal
Gaston Sanchez
3
Cuidado com itens nulos e classificação. Acabei no meu caso com strings para comparar como ", 2,2,3" e "2,2,3", que obviamente não são exatamente iguais.
barbara.post
2
Pode falhar para strings, ou seja, ['a', 'b']e ['a,b']. Eu recomendaria essa técnica apenas para pequenos scripts descartáveis.
alex
1
@alex - no meu caso, vírgulas são permitidas em strings, mas ponto e vírgula não, então usei ';' para entrar em vez de vírgula
a2345 soou em
45

Se você quiser verificar apenas se dois arrays têm os mesmos valores (independentemente do número de ocorrências e da ordem de cada valor), você pode fazer isso usando lodash :

_.isEmpty(_.xor(array1, array2))

Curto, simples e bonito!

Technotronic
fonte
1
Não consigo encontrar xornos documentos de sublinhado. Você está pensando em IODash?
Patrick Mencias-lewis
44
Array.prototype.compare = function(testArr) {
    if (this.length != testArr.length) return false;
    for (var i = 0; i < testArr.length; i++) {
        if (this[i].compare) { //To test values in nested arrays
            if (!this[i].compare(testArr[i])) return false;
        }
        else if (this[i] !== testArr[i]) return false;
    }
    return true;
}

var array1 = [2, 4];
var array2 = [4, 2];
if(array1.sort().compare(array2.sort())) {
    doSomething();
} else {
    doAnotherThing();
}

Talvez?

isakkarlsson
fonte
Obrigado! Funciona exatamente como desejado. Modifiquei um pouco a função para saber também quantos mismatches existem.
Carlos Precioso
falso para [2,4] [4,2].
Suraz Khanal
@SurazKhanal Ainda precisa classificar
Aaron McMillin
26

Por que seu código não funcionou

JavaScript possui tipos de dados primitivos e tipos de dados não primitivos.

Para tipos de dados primitivos, ==e ===verifique se os itens de cada lado das barras têm o mesmo valor. É por isso que 1 === 1é verdade.

Para tipos de dados não primitivos, como matrizes, ==e ===verifique a igualdade de referência. Ou seja, eles verificam se arr1e arr2são o mesmo objeto. Em seu exemplo, os dois arrays têm os mesmos objetos na mesma ordem, mas não são equivalentes.

Soluções

Duas matrizes, arr1e arr2, têm os mesmos membros se e somente se:

  • Tudo dentro arr2está dentroarr1

E

  • Tudo dentro arr1está dentroarr2

Então, isso vai resolver o problema (ES2016):

const containsAll = (arr1, arr2) => 
                arr2.every(arr2Item => arr1.includes(arr2Item))

const sameMembers = (arr1, arr2) => 
                        containsAll(arr1, arr2) && containsAll(arr2, arr1);

sameMembers(arr1, arr2); // `true`

Esta segunda solução usando Underscore está mais próxima do que você estava tentando fazer:

arr1.sort();
arr2.sort();

_.isEqual(arr1, arr2); // `true`

Funciona porque isEqualverifica a "igualdade profunda", o que significa que examina mais do que apenas igualdade de referência e compara valores.

Uma solução para sua terceira pergunta

Você também perguntou como descobrir quais coisas em arr1não estão contidas em arr2.

Isso bastará (ES2015):

const arr1 = [1, 2, 3, 4];
const arr2 = [3, 2, 1];

arr1.filter(arr1Item => !arr2.includes(arr1Item)); // `[4]`

Você também pode usar o differencemétodo do Underscore ::

_.difference(arr1, arr2); // `[4]`

ATUALIZAR

Veja o comentário de @Redu - minha solução serve sameMembers, mas o que você deve ter em mente sameMembersInOrdertambém é conhecido como deepEquals.

ATUALIZAÇÃO 2

Se você não se preocupa com a ordem dos membros dos arrays, ES2015 + Setpode ser uma estrutura de dados melhor do que Array. Consulte as notasisSupersetdifference do MDN sobre como implementar e usar patching perigoso.

Max Heiber
fonte
1
Suas soluções estão erradas. "Duas matrizes, arr1 e arr2, têm os mesmos membros se e somente se: Tudo em arr2 está em arr1 E Tudo em arr1 está em arr2" isso também está errado. Esta é uma matriz, não um conjunto. Portanto, sameMembers([1,1,2],[2,1,2]);deve retornar falso.
Redu
1
@Redu acho que depende do que "mesmos membros" significa - suponho que signifique "tem os mesmos membros". sameMembers([1,1,2],[2,1,2])deve retornar true, na minha opinião. sameMembersInOrder([1,1,2],[2,1,2])AKA deepEquals([1,1,2],[2,1,2])deve retornar false.
Max Heiber
Sua terceira solução arr1.filter...funcionará apenas para verificar se arr2 tem todos os elementos de arr1 ou não, mas não o contrário, que também é necessário.
Aakash Verma de
9

Verificação da igualdade do objeto:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

O teste acima também funciona com matrizes de objetos. Nesse caso, use uma função de classificação conforme documentado em http://www.w3schools.com/jsref/jsref_sort.asp

Pode ser suficiente para pequenos arrays com esquemas JSON simples.

Sandeep
fonte
9

Nosso objetivo é basicamente verificar se 2 arrays são conjuntos iguais. set é o conjunto definido matematicamente . A classificação mais rápida assintoticamente leva tempo O (nlog (n)) . Portanto, se você classificar um array, levará pelo menos O (nlog (n)) tempo. Mas você pode fazer essa tarefa mais rápido , que assintoticamente leva tempo O (n) (caso médio, não pior caso) com uma estrutura de dados de dicionário. Em JS, um dicionário é simplesmente um objeto com chaves e valores.

/** assumes array elements are primitive types
* check whether 2 arrays are equal sets.
* @param  {} a1 is an array
* @param  {} a2 is an array
*/
function areArraysEqualSets(a1, a2) {
  const superSet = {};
  for (const i of a1) {
    const e = i + typeof i;
    superSet[e] = 1;
  }

  for (const i of a2) {
    const e = i + typeof i;
    if (!superSet[e]) {
      return false;
    }
    superSet[e] = 2;
  }

  for (let e in superSet) {
    if (superSet[e] === 1) {
      return false;
    }
  }

  return true;
}

Observe que esta função funciona com arrays de tipos primitivos e assume a1e a2são arrays.

canbax
fonte
5

Que tal isso? ES 2017 eu suponho:

const array1 = [1, 3, 5];
const array2 = [1, 5, 3];

const isEqual = (array1.length === array2.length) && (array1.every(val => array2.includes(val)));
console.log(isEqual);

A 1ª condição verifica se ambas as matrizes têm o mesmo comprimento e a 2ª condição verifica se a 1ª matriz é um subconjunto da 2ª matriz. A combinação dessas 2 condições deve resultar na comparação de todos os itens das 2 matrizes, independentemente da ordem dos elementos.

O código acima só funcionará se ambas as matrizes tiverem itens não duplicados.

Ramandeep Singh
fonte
3

Quando você compara esses dois arrays, está comparando os objetos que representam os arrays, não o conteúdo.

Você terá que usar uma função para comparar os dois. Você pode escrever o seu próprio que simplesmente faz um loop em um e o compara com o outro depois de verificar se os comprimentos são iguais.

Andrew
fonte
3

Solução simples para igualdade superficial usando ES6:

const arr1test = arr1.slice().sort()
const arr2test = arr2.slice().sort()
const equal = !arr1test.some((val, idx) => val !== arr2test[idx])

Cria cópias superficiais de cada matriz e as classifica. Em seguida, usa some()para percorrer os arr1testvalores, verificando cada valor em relação ao valor arr2testdo mesmo índice. Se todos os valores forem iguais, some()retorna falsee, por sua vez, equalavalia como true.

Também poderia usar every(), mas teria que percorrer todos os elementos da matriz para satisfazer um trueresultado, ao passo que some()desaparecerá assim que encontrar um valor diferente de:

const equal = arr1test.every((val, idx) => val === arr2test[idx])
filete
fonte
2

Eu tinha valores inteiros simples em um projeto de jogo.
Tinha menos número de valores em cada array, também precisava daquele array original intocado.
Então, eu fiz o abaixo, funcionou bem. (Código editado para colar aqui)

var sourceArray = [1, 2, 3];
var targetArray = [3, 2, 1];

if (sourceArray.length !== targetArray.length) {
    // not equal
    // did something
    return false;
}

var newSortedSourceArray = sourceArray.slice().sort();
var newSortedTargetArray = targetArray.slice().sort();

if (newSortedSourceArray.toString() !== newSortedTargetArray.toString()) { // MAIN CHECK
    // not equal
    // did something
    return false;
}
else {
    // equal
    // did something
    // continued further below
}

// did some more work

return true;

Espero que ajude.

Manohar Reddy Poreddy
fonte
2

Usando ES6

Usaremos a equalsfunção de Ramda , mas em vez disso podemos usar Lodash ou Underscore isEqual:

const R = require('ramda');

const arraysHaveSameValues = (arr1, arr2) => R.equals( [...arr1].sort(), [...arr2].sort() )

Usando o spread opporator, evitamos a mutação dos arrays originais e mantemos nossa função pura.

Ben Carp
fonte
2

Você pode usar em reducevez de loops para parecer inteligente, mas correndo o risco de que seus colegas desenvolvedores pensem em você como um espertinho.

function isArrayContentSame(a, b) {
  if (Array.isArray(a) && Array.isArray(b) && a.length == b.length) {
    a = a.concat().sort()
    b = b.concat().sort()
    return a.reduce((acc,e,i) => acc && e === b[i], true)
  } else {
    return false;
  }
}
Bemmu
fonte
1

Se os itens na matriz forem primitivos (números ou caracteres únicos), você pode usar uma combinação de comprimentos de comparação e conjuntos.

function equalArrayItems(arr1, arr2) {
  if (arr1.length !== arr2.length) return false
  const set1 = new Set(arr1)
  const set2 = new Set(arr2)
  const set3 = new Set(arr1, arr2)
  return set1.size === set3.size && set2.size === set3.size
}
Stefan Musarra
fonte
1

Já estamos em 2020, mas notei que a maioria das outras soluções usam sort, O (n * log n), usam bibliotecas ou têm complexidade O (n ^ 2).

Aqui está uma solução Javascript pura com complexidade linear, O (n):

/**
 * Check if two arrays of strings or numbers have the same values regardless of the order
 * @param {string[]|number[]} arr1
 * @param {string[]|number[]} arr2
 * @return {boolean}
 */    
compareArrays = (arr1, arr2) => {
    if (arr1.length !== arr2.length) return false;
    const lk1 = {};
    const lk2 = {};
    let i = arr1.length;
    while (--i >= 0) {
        lk1[arr1[i]] = true;
        lk2[arr2[i]] = true
    }
    i = arr1.length;
    while (--i >= 0) {
        const v = arr1[i];
        if (lk1[v] !== lk2[v]) return false;
    }
    return true
}

Testes:

compareArrays([2, 4], [4, 2]) => true
compareArrays([2, 4], [4, 2, 7]) => false
compareArrays([], []) => true
SC1000
fonte
1
Ei, essa é uma entrada incrível! É bastante complicado, mas faz sentido. Tenho uma pergunta: não estou muito familiarizado com a notação Big O, mas certamente esse algoritmo é O (2n)? Mas não pense que isso faz muita diferença.
Carlos Precioso
1
@CarlosPrecioso Correto e O (2n) = O (n). A complexidade não muda multiplicando por um fator constante
SC1000
0

Se você estiver usando o Prototype Framework, você pode usar o método intersect de uma matriz para descobrir se eles são os mesmos (independentemente da ordem):

var array1 = [1,2];
var array2 = [2,1];

if(array1.intersect(array2).length === array1.length) {
    alert("arrays are the same!");
}
Erfan
fonte
Isso não funciona - [1,2].intersect([1,2,3]).length === [1,2].lengthretorna verdadeiro. Você deve comparar o comprimento dos arrays originais também, eu editei o post para demonstrar.
GMA
Na verdade, acabei de perceber que minha edição sugerida não funciona no caso de duplicatas ... por exemplo, ela retornará falso para array1 = [1,1,2]; array2 = [1,1,2];... a resposta original não falha para essa entrada.
GMA
Você pode fazer o oposto com_.difference(array1, array2).length;
Vic
0

por favor, verifique esta resposta

var arr1= [12,18];
var arr2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];
for(i=0;i<arr1.length;i++)
{
var array1=arr1[i];
for(j=0;j<arr2.length;j++)
{
    var array2=arr2[j];
    if(array1==array2)
    {
return true;
    }
}
}
Vinoth
fonte
2
Isso é funcionalmente equivalente a esta resposta , exceto por alguns erros. Primeiro, tudo isso deve ser agrupado em uma função, ou o returnnão terá efeito. Em segundo lugar, você deve verificar os arrays classificados, pois [1,2]e [2,1]serão detectados como diferentes. Terceiro e mais importante, isso realmente só verificará se algum elemento é o mesmo. O condicional deve ser if (array1!==array2) {return false;}. Talvez isso possa ajudá-lo no futuro!
Carlos Precioso
1
E como um comentário extra, tente usar indentação para melhor compreensão do fluxo do código, bem como nomes de variáveis ​​mais claros. Ex: array1e array2pode ser renomeado elem1e elem2. Essas duas dicas vão lhe poupar muitas dores de cabeça no futuro!
Carlos Precioso
2
Em uma inspeção mais aprofundada, por que o laço duplo? Ambas as matrizes devem ter o mesmo comprimento e, caso contrário, não são diretamente iguais. Dessa forma, você pode usar apenas um loop. Neste momento, este código verifica se algum dos elementos do primeiro array está em algum lugar do segundo. Verifique esta resposta para ver como você deve implementá-la. Boa sorte em sua jornada pelo JavaScript!
Carlos Precioso
0

Respondendo depois de muito tempo, mas espero que isso ajude alguém que procura uma solução simples e novatos modernos.

Agora podemos conseguir isso usando várias bibliotecas como lodash, underscoreetc. (Isso se torna parte do projeto hoje em dia devido à simplicidade, vários recursos e alto uso)

Você pode usar o cruzamento da biblioteca Lodash.

_.intersection(['2-1', '1'], ['2-2', '3-1', '2-1']); 
// => ['2-1']

Isso funcionará para qualquer tipo de dados.

Prasanth Jaya
fonte
0

Se você quiser comparar dois arrays e verificar se algum objeto é o mesmo em ambos os arrays, funcionará. Exemplo:

Matriz1 = [a, b, c, d]
Matriz2 = [d, e, f, g]

Aqui, 'd' é comum em ambas as matrizes, portanto, esta função retornará o valor verdadeiro.

  cehckArray(array1, array2) {
    for (let i = 0; i < array1.length; i++) {
      for (let j = 0; j < array2.length; j++) {
        if (array1[i] === array2[j]) {
          return true;
        }
      }
    }
    // Return if no common element exist 
    return false;
  }
Sandip Moradiya
fonte
0

Tente isto

function arraysEqual(arr1, arr2){
    if (!Array.isArray(arr1) || !Array.isArray(arr2) || arr1.length!=arr2.length)
        return false;

    return arr1.length==arr1.filter(word => arr2.includes(word)).length;
}
Dimitrios Stefos
fonte
0

Eu tenho outra maneira baseada na resposta aceita.

function compareArrays(array1, array2) {

    if (
        !Array.isArray(array1)
        || !Array.isArray(array2)
        || array1.length !== array2.length
    ) return false;

    var first = array1.sort().map(value => (String(value))).join();
    var second = array2.sort().map(value => (String(value))).join();

    return first == second ? true : false;
}
Cristopher Paniagua
fonte
Ei, bem-vindo ao StackOverflow! Embora essa resposta funcione em alguns casos, há alguns casos específicos em que não. Primeiro, esteja ciente de que o .sort () modifica o array original. Hoje em dia isso é considerado falta de higiene, por isso a resposta original faz um .concat () primeiro, para fazer uma cópia.
Carlos Precioso
E, segundo ponto, isso não funcionaria de forma consistente com o resto do JavaScript. {foo: "bar"} === {foo: "bar"} retorna falso (eles são dois objetos distintos criados separadamente); então compareArrays ([{foo: "bar"}], [{foo: "bar"}]), também deve retornar falso para consistência. No entanto, com a sua implementação, ele retorna verdadeiro, pois a representação da string dos objetos é a mesma. Esse poderia ser um comportamento desejado ou não, mas um comportamento a ser considerado em qualquer caso.
Carlos Precioso
0

Uma função para comparar dois Arrays, para verificar se ambos têm os mesmos elementos. Mesmo se eles estiverem fora de serviço ...

É bom para arrays simples. [String, Number, Boolean, null, NaN].

Eu não uso .sort (), ele modifica o array original. Alguns dizem que é ruim ...

Cuidado. Esta função é limitada, ela não pode comparar objetos "[], {}" ou funções dentro desses Arrays, os próprios arrays são Objetos.

   let arraysHasSameElements = (arr1, arr2) => {
        let count =
            // returns counting of occurrences.
            (arr, val) => arr.reduce((count, curr) => (curr === val ? 1 : 0) + count, 0);

        /* this will return true if lengths of the arrays is equal.
           then compare them.*/
        return arr1.length === arr2.length

            // compare arr1 against arr2.
            && arr1.reduce((checks, val) =>

                /*  creating array of checking if a value has equal amount of occurrences
                    in both arrays, then adds true 'check'. */
                checks.concat(count(arr1, val) === count(arr2, val)), [])

                // checking if each check is equal to true, then .every() returns true.
                .every(check => check);
    }

    let arr1 = ['',-99,true,NaN,21,null,false,'help',-99,'help',NaN], 
        arr2 = [null,-99,'',NaN,NaN,false,true,-99,'help',21,'help'];
    arraysHasSameElements(arr1, arr2); //true

    let arr3 = [false,false,false,false,false,false], 
        arr4 = [false,false,false,false,false,false]
    arraysHasSameElements(arr3, arr4); //true


    // here we have uncommented version.
    let arraysHasSameElements = (arr1, arr2) => {
        let count = (arr, val) => arr.reduce((count, curr) => (curr === val ? 1:0) + count, 0);
        return arr1.length === arr2.length && arr1.reduce((checks, val) =>
            checks.concat(count(arr1, val) === count(arr2, val)), []).every(check => check);
    }
Magnus Fohlström
fonte
-1

Solução simples para comparar os dois arrays:

var array1 = [2, 4];
var array2 = [4, 2];

array1.sort();
array2.sort();

if (array1[0] == array2[0]) {
    console.log("Success");
}else{
    console.log("Wrong");
}
Luqman Shofuleji
fonte