Cómo saber si dos matrices tienen los mismos valores

104

Tengo estas dos matrices: una está llena de información de una solicitud ajax y otra almacena los botones en los que el usuario hace clic. Yo uso este código (lo llené con números de muestra):

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();
}

Pero siempre da false, incluso si las dos matrices son iguales, pero con un nombre diferente. (Verifiqué esto en la consola JS de Chrome). Entonces, ¿hay alguna forma de que pueda saber si estas dos matrices contienen lo mismo? ¿Por qué está dando false? ¿Cómo puedo saber qué valores de la primera matriz no están en la segunda?

Carlos Precioso
fuente
1
Estoy bastante seguro de que debe revisar cada elemento de las matrices.
Thomas Li
¿Sabes por qué devuelve falso? Curioso.
RobW
Vea la respuesta de @Andrew stackoverflow.com/a/6229263/702565
Carlos Precioso

Respuestas:

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;

}

Tenga en cuenta que esto no modifica las matrices originales a diferencia de una respuesta anterior.

Maciej Krawczyk
fuente
2
la clasificación lleva nlog (n) tiempo. No necesita ordenar. Esta respuesta stackoverflow.com/a/55614659/3209523 funciona en tiempo lineal.
canbax
El uso de mecanografiado Array.isArray () estaba causando errores, eliminando que funcionaba bien.
Ariel Frischer
88

Si los elementos de su matriz no son objetos, si son números o cadenas, por ejemplo, puede comparar sus cadenas unidas para ver si tienen los mismos miembros en cualquier orden.

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
fuente
2
Esto funcionará bien para primitivas u objetos que tienen valores toString de identificación única, pero no para cualquier objeto.
devios1
¡Gracias! solución ordenada
Gaston Sanchez
3
Tenga cuidado con los elementos nulos y la clasificación. Terminé en mi caso con cadenas para comparar como ", 2,2,3" y "2,2,3", que por supuesto no son estrictamente iguales.
barbara.post
2
Podría fallar por cadenas, es decir, ['a', 'b']y ['a,b']. Solo recomendaría esta técnica para pequeños guiones desechables.
alex
1
@alex: en mi caso, las comas están permitidas en cadenas pero no el punto y coma, así que usé ';' unirse en lugar de coma
a2345sooted
45

Si desea verificar solo si dos matrices tienen los mismos valores (independientemente del número de ocurrencias y el orden de cada valor), puede hacerlo usando lodash :

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

¡Corto, sencillo y bonito!

Technotronic
fuente
1
¿Parece que no puedo encontrar xoren los documentos de subrayado? ¿Estás pensando en 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();
}

¿Tal vez?

isakkarlsson
fuente
¡Gracias! Funciona como se desea. Modifiqué un poco la función para poder saber también cuántos desajustes hay.
Carlos Precioso
falso para [2,4] [4,2].
Suraz Khanal
@SurazKhanal Todavía necesito ordenar
Aaron McMillin
26

Por qué tu código no funcionó

JavaScript tiene tipos de datos primitivos y tipos de datos no primitivos.

Para los tipos de datos primitivos, ==y ===comprobación de si las cosas a ambos lados de las barras tienen el mismo valor. Por eso 1 === 1es verdad.

Para tipos de datos no primitivos como matrices, ==y ===verifique la igualdad de referencia. Es decir, comprueban si arr1y arr2son el mismo objeto. En su ejemplo, las dos matrices tienen los mismos objetos en el mismo orden, pero no son equivalentes.

Soluciones

Dos matrices, arr1y arr2, tienen los mismos miembros si y solo si:

  • Todo arr2está enarr1

Y

  • Todo arr1está enarr2

Entonces esto funcionará (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 solución que usa Underscore está más cerca de lo que estaba tratando de hacer:

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

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

Funciona porque isEqualcomprueba la "igualdad profunda", lo que significa que busca algo más que la igualdad de referencia y compara valores.

Una solución a tu tercera pregunta

También preguntó cómo averiguar qué cosas arr1no están incluidas arr2.

Esto lo hará (ES2015):

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

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

También puede usar el differencemétodo de Underscore :

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

ACTUALIZAR

Vea el comentario de @ Redu: mi solución es para sameMembers, pero lo que puede tener en mente sameMembersInOrdertambién se conoce como deepEquals.

ACTUALIZACIÓN 2

Si no le importa el orden de los miembros de las matrices, ES2015 + Setpuede ser una mejor estructura de datos que Array. Consulte las notas de MDN sobre cómo implementar isSupersetydifference usar parches de mono peligrosos.

Max Heiber
fuente
1
Tus soluciones están equivocadas. "Dos matrices, arr1 y arr2, tienen los mismos miembros si y solo si: Todo en arr2 está en arr1 Y todo en arr1 está en arr2" esto también es incorrecto. Esta es una matriz, no un conjunto. Entonces sameMembers([1,1,2],[2,1,2]);debería devolver falso.
Reducción el
1
@Redu supongo que depende de lo que signifique "mismos miembros"; entiendo que significa "tiene los mismos miembros". sameMembers([1,1,2],[2,1,2])debería volver true, en mi opinión. sameMembersInOrder([1,1,2],[2,1,2])AKA deepEquals([1,1,2],[2,1,2])debería regresar false.
Max Heiber
Su tercera solución arr1.filter...solo funcionará para verificar si arr2 tiene todos los elementos de arr1 o no, pero no al revés, lo que también se requiere.
Aakash Verma
9

Comprobación de igualdad de objetos:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

La prueba anterior también funciona con matrices de objetos, en cuyo caso use una función de clasificación como se documenta en http://www.w3schools.com/jsref/jsref_sort.asp

Podría ser suficiente para arreglos pequeños con esquemas JSON planos.

Sandeep
fuente
9

Nuestro objetivo es básicamente comprobar si 2 matrices son conjuntos iguales. conjunto es el conjunto definido matemáticamente . La clasificación más rápida asintóticamente toma O (nlog (n)) tiempo. Entonces, si ordena una matriz, tomaría al menos O (nlog (n)) tiempo. Pero puede hacer esta tarea más rápido , lo que asintóticamente toma O (n) tiempo (caso promedio, no el peor de los casos) con una estructura de datos de diccionario. En JS, un diccionario es simplemente un objeto con claves y 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;
}

Tenga en cuenta que esta función trabaja con matrices de tipos primitivos y asume a1y a2son matrices.

canbax
fuente
5

¿Qué pasa con esto? ES 2017 supongo:

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);

La primera condición comprueba si ambas matrices tienen la misma longitud y la segunda condición comprueba si la primera matriz es un subconjunto de la segunda matriz. La combinación de estas 2 condiciones debería dar como resultado la comparación de todos los elementos de las 2 matrices independientemente del orden de los elementos.

El código anterior solo funcionará si ambas matrices tienen elementos no duplicados.

Ramandeep Singh
fuente
3

Cuando compara esas dos matrices, está comparando los objetos que representan las matrices, no el contenido.

Tendrás que usar una función para comparar los dos. Puede escribir el suyo propio que simplemente pase por uno y lo compare con el otro después de comprobar que las longitudes son las mismas.

Andrés
fuente
3

Solución simple para la igualdad superficial usando ES6:

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

Crea copias superficiales de cada matriz y las ordena. Luego usa some()para recorrer los arr1testvalores, verificando cada valor con el valor arr2testcon el mismo índice. Si todos los valores son iguales, some()devuelve falsey, a su vez, equalevalúa como true.

También podría usar every(), pero tendría que recorrer todos los elementos de la matriz para satisfacer un trueresultado, mientras que some()se rescatará tan pronto como encuentre un valor que no sea igual:

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

Tenía valores enteros simples en un proyecto de juego.
Tenía menos valores en cada matriz, además, necesitaba esa matriz original intacta.
Entonces, hice lo siguiente, funcionó bien. (Código editado para pegar aquí)

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 ayude.

Manohar Reddy Poreddy
fuente
2

Usando ES6

Usaremos la equalsfunción de Ramda , pero en su lugar podemos usar la de Lodash o la de Underscore isEqual:

const R = require('ramda');

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

Usando el opporator de propagación, evitamos mutar las matrices originales y mantenemos nuestra función pura.

Ben Carp
fuente
2

Puedes usar reducebucles en lugar de para parecer inteligente, pero a riesgo de que tus compañeros desarrolladores te consideren un sabelotodo.

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
fuente
1

Si los elementos de la matriz son primitivos (números o caracteres individuales), puede usar una combinación de comparar longitudes y usar 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
fuente
1

Ya es 2020, pero noté que la mayoría de las otras soluciones usan sort, O (n * log n), usan bibliotecas o tienen complejidad O (n ^ 2).

Aquí hay una solución Javascript pura con complejidad lineal, 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
}

Pruebas:

compareArrays([2, 4], [4, 2]) => true
compareArrays([2, 4], [4, 2, 7]) => false
compareArrays([], []) => true
SC1000
fuente
1
¡Oye, esa es una entrada increíble! Es bastante complicado pero tiene sentido. Tengo una pregunta: no estoy muy familiarizado con la notación Big O, pero seguramente este algoritmo es O (2n). Sin embargo, no crea que eso hace mucha diferencia.
Carlos Precioso
1
@CarlosPrecioso Eso es correcto y O (2n) = O (n). La complejidad no cambia multiplicando por un factor constante
SC1000
0

Si está utilizando Prototype Framework, puede usar el método de intersección de una matriz para averiguar si son iguales (independientemente del orden):

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

if(array1.intersect(array2).length === array1.length) {
    alert("arrays are the same!");
}
Erfan
fuente
Esto no funciona, [1,2].intersect([1,2,3]).length === [1,2].lengthdevuelve verdadero. También debe comparar la longitud de las matrices originales, he editado la publicación para demostrarlo.
GMA
En realidad, me acabo de dar cuenta de que mi edición sugerida no funciona en el caso de duplicados ... por ejemplo, devolverá falso para array1 = [1,1,2]; array2 = [1,1,2];... la respuesta original no falla para esa entrada.
GMA
Puede hacer lo contrario con_.difference(array1, array2).length;
Vic
0

amablemente revisa esta respuesta

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
fuente
2
Esto es funcionalmente equivalente a esta respuesta , salvo por un par de errores. Primero, todo esto debe estar envuelto dentro de una función, o returnno tendrá ningún efecto. En segundo lugar, debe verificar las matrices ordenadas, ya que [1,2]y [2,1]se detectarán como no iguales. En tercer lugar y más importante, esto solo verificará si algún elemento es el mismo. El condicional debería ser if (array1!==array2) {return false;}. ¡Quizás esto pueda ayudarte en el futuro!
Carlos Precioso
1
Y como comentario adicional, intente usar sangría para comprender mejor el flujo de código, así como nombres de variables más claros. Por ejemplo: array1y array2podría cambiarse de nombre elem1y elem2. ¡Ambos consejos le ahorrarán muchos dolores de cabeza en el futuro!
Carlos Precioso
2
En una inspección más profunda, ¿por qué el doble bucle? Ambas matrices deben tener la misma longitud y, de lo contrario, no son directamente iguales. De esta forma, solo puede utilizar un bucle. En este momento, este código verifica si alguno de los elementos de la primera matriz está en algún lugar de la segunda. Consulte esta respuesta para ver cómo debe implementarla. ¡Buena suerte en tu viaje con JavaScript!
Carlos Precioso
0

Respondiendo después de mucho tiempo, pero espero que esto ayude a alguien que busca una solución simple y novatos modernos.

Ahora podemos lograr esto utilizando varias bibliotecas como lodash, underscore, etc. (Estos se convierte en parte del proyecto hoy en día debido a la simplicidad, características múltiples y el uso de alta)

Puede usar la intersección de la biblioteca lodash.

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

Esto funcionará para cualquier tipo de datos.

Prasanth Jaya
fuente
0

Si desea comparar dos matrices y comprobar si algún objeto es el mismo en ambas matrices, funcionará. Ejemplo:

Array1 = [a, b, c, d]
Array2 = [d, e, f, g]

Aquí, 'd' es común en ambos arreglos, por lo que esta función devolverá un valor verdadero.

  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
fuente
0

Prueba esto

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
fuente
0

Tengo otra forma basada en la respuesta aceptada.

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
fuente
¡Bienvenidos a StackOverflow! Si bien esta respuesta funcionaría en algunos casos, habría algunos casos específicos en los que no lo haría. En primer lugar, tenga en cuenta que .sort () modifica la matriz original. Hoy en día eso se considera mala higiene, por eso la respuesta original hace un .concat () primero, para hacer una copia.
Carlos Precioso
Y segundo punto, esto no funcionaría de manera consistente con el resto de JavaScript. {foo: "bar"} === {foo: "bar"} devuelve falso (son dos objetos distintos creados por separado); así que compareArrays ([{foo: "bar"}], [{foo: "bar"}]), también debería devolver falso para mantener la coherencia. Sin embargo, con su implementación, devuelve verdadero, ya que la representación de cadena de los objetos es la misma. Ese podría ser un comportamiento deseado, o no, pero uno a tener en cuenta en cualquier caso.
Carlos Precioso
0

Una función para comparar dos matrices, para comprobar si ambas tienen los mismos elementos. Incluso si están fuera de servicio ...

Es bueno para arreglos simples. [Cadena, Número, Booleano, Nulo, NaN].

No uso .sort (), modifica la matriz original. Algunos dicen que es malo ...

Precaución. Esta función es limitada, no puede comparar objetos "[], {}" o funciones dentro de estos arreglos, los arreglos en sí mismos son 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
fuente
-1

Solución simple para comparar las dos matrices:

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
fuente