objetos - compare objects javascript
¿Cómo comparar arrays en JavaScript? (30)
Me gustaría comparar dos matrices ... idealmente, eficientemente. Nada lujoso, solo true
si son idénticos, y false
si no. No en vano, el operador de comparación no parece 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
JSON codifica cada matriz, pero ¿hay una manera más rápida o "mejor" de simplemente comparar matrices sin tener que iterar a través de cada valor?
El camino practico
Creo que es incorrecto decir que una implementación en particular es "The Right Way ™" si es solo "correcto" ("correcto") en contraste con una solución "incorrecta". La solución de Tomáš es una clara mejora con respecto a la comparación de matrices basada en cadenas, pero eso no significa que sea objetivamente "correcto". ¿Qué es lo correcto de todos modos? ¿Es el más rápido? ¿Es el más flexible? ¿Es lo más fácil de comprender? ¿Es el más rápido de depurar? ¿Utiliza las menos operaciones? ¿Tiene efectos secundarios? Ninguna solución puede tener lo mejor de todas las cosas.
Tomáš podría decir que su solución es rápida, pero también diría que es innecesariamente complicada. Intenta ser una solución todo en uno que funcione para todos los arreglos, anidados o no. De hecho, incluso acepta más que simples arreglos como entrada y aún intenta dar una respuesta "válida".
Los genéricos ofrecen reutilización.
Mi respuesta abordará el problema de manera diferente. Comenzaré con un procedimiento genérico de arrayCompare
que solo se ocupa de arrayCompare
las matrices. A partir de ahí, construiremos nuestras otras funciones de comparación básicas como arrayEqual
y arrayDeepEqual
, etc.
// 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)
En mi opinión, el mejor tipo de código ni siquiera necesita comentarios, y esto no es una excepción. Aquí ocurre tan poco que puede comprender el comportamiento de este procedimiento casi sin esfuerzo. Claro, parte de la sintaxis de ES6 puede parecerle extraña ahora, pero eso es solo porque ES6 es relativamente nuevo.
Como sugiere el tipo, arrayCompare
toma la función de comparación, f
, y dos matrices de entrada, xs
y ys
. En su mayor parte, todo lo que hacemos es llamar a f (x) (y)
para cada elemento en las matrices de entrada. Devolvemos una false
anticipada si la f
definida por el usuario devuelve false
, gracias a la evaluación de cortocircuito de &&
. Entonces, sí, esto significa que el comparador puede detener la iteración anticipada y evitar el bucle en el resto de la matriz de entrada cuando no sea necesario.
Comparación estricta
A continuación, utilizando nuestra función arrayCompare
, podemos crear fácilmente otras funciones que podamos necesitar. Comenzaremos con el arrayEqual
elemental ...
// 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
Simple como eso. arrayEqual
se puede definir con arrayCompare
y una función de comparación que compara arrayCompare
usando ===
(para igualdad estricta).
Note que también definimos equal
como su propia función. Esto resalta el rol de arrayCompare
como una función de orden superior para utilizar nuestro comparador de primer orden en el contexto de otro tipo de datos (Array).
Comparación suelta
Podríamos definir arrayLooseEqual
con la misma arrayLooseEqual
utilizando a ==
lugar. Ahora, al comparar 1
(Número) con ''1''
(Cadena), el 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
Comparación profunda (recursiva)
Probablemente has notado que esto es solo una comparación superficial, aunque. Seguramente la solución de Tomáš es "The Right Way ™" porque hace una comparación profunda implícita, ¿verdad?
Bueno, nuestro procedimiento arrayCompare
es lo suficientemente versátil como para usarlo de una manera que hace que una prueba de igualdad profunda sea una brisa ...
// 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
Simple como eso. Construimos un comparador profundo utilizando otra función de orden superior. Esta vez estamos envolviendo arrayCompare
usando un comparador personalizado que verificará si a
y b
son matrices. Si es así, arrayDeepCompare
aplicar arrayDeepCompare
contrario, compare a
y b
con el comparador especificado por el usuario ( f
). Esto nos permite mantener el comportamiento de comparación profunda separado de la forma en que realmente comparamos los elementos individuales. Es decir, como se muestra en el ejemplo anterior, podemos realizar una comparación profunda utilizando equal
, looseEqual
o cualquier otro comparador que hagamos.
Debido a que arrayDeepCompare
está en curry, podemos aplicarlo parcialmente como lo hicimos en los ejemplos anteriores también
// arrayDeepEqual :: [a] -> [a] -> Bool
const arrayDeepEqual =
arrayDeepCompare (equal)
// arrayDeepLooseEqual :: [a] -> [a] -> Bool
const arrayDeepLooseEqual =
arrayDeepCompare (looseEqual)
Para mí, esto ya es una clara mejora con respecto a la solución de Tomáš porque puedo elegir explícitamente una comparación superficial o profunda para mis arreglos, según sea necesario.
Comparación de objetos (ejemplo)
Ahora, ¿qué pasa si tienes una matriz de objetos o algo? Tal vez quiera considerar esas matrices como "iguales" si cada objeto tiene el mismo valor de id
...
// 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
Simple como eso. Aquí he usado objetos JS de vainilla, pero este tipo de comparador podría funcionar para cualquier tipo de objeto; incluso sus objetos personalizados. La solución de Tomáš tendría que ser completamente reelaborada para apoyar este tipo de prueba de igualdad
Arreglo profundo con objetos? No es un problema. Construimos funciones genéricas altamente versátiles, por lo que funcionarán en una amplia variedad 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
Comparación arbitraria (ejemplo)
¿O qué pasaría si quisiera hacer algún otro tipo de comparación completamente arbitraria? Tal vez quiero saber si cada x
es mayor que cada 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 es más
Puedes ver que en realidad estamos haciendo más con menos código. No hay nada complicado en arrayCompare
, y cada uno de los comparadores personalizados que hemos creado tiene una implementación muy simple.
Con facilidad, podemos definir exactamente cómo deseamos que se comparen dos arreglos: poco profundos, profundos, estrictos, sueltos, alguna propiedad del objeto, o algún cálculo arbitrario, o cualquier combinación de estos, todo con un solo procedimiento , arrayCompare
. Tal vez incluso soñar con un comparador RegExp
! Sé cómo los niños aman esas expresiones regulares ...
¿Es el más rápido? No Pero probablemente tampoco necesita serlo. Si la velocidad es la única métrica utilizada para medir la calidad de nuestro código, se desechará una gran cantidad de código realmente bueno. Es por eso que llamo a este enfoque el método práctico . O tal vez para ser más justo, de una manera práctica. Esta descripción es adecuada para esta respuesta porque no estoy diciendo que esta respuesta solo sea práctica en comparación con alguna otra respuesta; es objetivamente cierto. Hemos alcanzado un alto grado de practicidad con muy poco código sobre el que es muy fácil razonar. Ningún otro código puede decir que no hemos obtenido esta descripción.
¿Eso lo convierte en la solución "correcta" para usted? Eso depende de usted para decidir. Y nadie más puede hacer eso por ti; solo tu sabes cuales son tus necesidades En casi todos los casos, valoro el código directo, práctico y versátil en vez de inteligente y rápido. Lo que usted valora puede diferir, así que elija lo que le funcione.
Editar
Mi antigua respuesta estaba más centrada en descomponer arrayEqual
en pequeños procedimientos. Es un ejercicio interesante, pero no es realmente la mejor manera (más práctica) de abordar este problema. Si estás interesado, puedes ver este historial de revisiones.
A partir de la respuesta de Tomáš Zato, estoy de acuerdo en que solo recorrer las matrices es el más rápido. Además (como han dicho otros), la función debería llamarse igual / igual, no comparar. A la luz de esto, modifiqué la función para manejar la comparación de arrays en busca de similitud, es decir, tienen los mismos elementos, pero fuera de orden, para uso personal, y pensé que la pondría aquí para que todos la vean.
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;
}
Esta función toma un parámetro adicional de estricto que por defecto es verdadero. Este parámetro estricto define si las matrices deben ser totalmente iguales tanto en el contenido como en el orden de esos contenidos, o simplemente contener el mismo contenido.
Ejemplo:
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
También he escrito un jsfiddle rápido con la función y este ejemplo:
http://jsfiddle.net/Roundaround/DLkxX/
Creo que esta es la forma más sencilla de hacerlo utilizando JSON stringify, y puede ser la mejor solución en algunas situaciones:
JSON.stringify(a1) === JSON.stringify(a2);
Esto convierte los objetos a1
y a2
en cadenas para que puedan compararse. El orden es importante en la mayoría de los casos, ya que puede ordenar el objeto utilizando un algoritmo de clasificación que se muestra en una de las respuestas anteriores.
Tenga en cuenta que ya no está comparando el objeto sino la representación de cadena del objeto. Puede que no sea exactamente lo que quieres.
En el espíritu de la pregunta original:
Me gustaría comparar dos matrices ... idealmente, eficientemente . Nada lujoso , solo verdadero si son idénticos, y falso si no.
He estado ejecutando pruebas de rendimiento en algunas de las sugerencias más simples que se proponen aquí con los siguientes results (rápido a lento):
while (67%) por Tim Down
var i = a1.length;
while (i--) {
if (a1[i] !== a2[i]) return false;
}
return true
every (69%) por usuario2782196
a1.every((v,i)=> v === a2[i]);
reduce (74%) por DEIs
a1.reduce((a, b) => a && a2.includes(b), true);
join & toString (78%) por Gaizka Allende & vivek
a1.join('''') === a2.join('''');
a1.toString() === a2.toString();
Media toString (90%) por Victor Palomo
a1 == a2.toString();
stringify (100%) por Radtek
JSON.stringify(a1) === JSON.stringify(a2);
Tenga en cuenta que los ejemplos a continuación asumen que las matrices son ordenadas, matrices unidimensionales.
.length
comparación de.length
se ha eliminado para un punto de referencia común (agreguea1.length === a2.length
a cualquiera de las sugerencias y obtendrá un aumento de rendimiento de ~ 10%). Elija las soluciones que más le convengan, sabiendo la velocidad y la limitación de cada una.Nota no relacionada: es interesante ver a las personas que tienen a John Waynes feliz con los disparadores en el botón de voto negativo en respuestas perfectamente legítimas a esta pregunta.
En las mismas líneas que JSON.encode es 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
El único problema es si le importan los tipos que la última comparación prueba. Si te interesan los tipos, tendrás que hacer un bucle.
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
Si el orden debe seguir siendo el mismo, de lo que es solo un bucle, no se necesita ningún ordenamiento.
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
Me gusta usar la biblioteca Underscore para proyectos de codificación pesada de matriz / objeto ... en Underscore y Lodash, si estás comparando matrices u objetos, se ve así:
_.isEqual(array1, array2) // returns a boolean
_.isEqual(object1, object2) // returns a boolean
No está claro qué quiere decir con "idéntico". Por ejemplo, ¿son las matrices a
y b
inferiores idénticas (tenga en cuenta las matrices anidadas)?
var a = ["foo", ["bar"]], b = ["foo", ["bar"]];
Aquí hay una función de comparación de matrices optimizada que compara los elementos correspondientes de cada matriz a su vez utilizando una igualdad estricta y no hace una comparación recursiva de los elementos de la matriz que son matrices, lo que significa que para el ejemplo anterior, arraysIdentical(a, b)
devolvería false
Funciona en el caso general, en el que las soluciones basadas en JSON y join()
no:
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;
};
Para comparar matrices, recorrelas y compara cada valor:
Comparando matrices:
// 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;
Puede decir " Pero es mucho más rápido comparar cadenas, no hay bucles ... " bueno, entonces debe tener en cuenta que existen bucles. Primer bucle recursivo que convierte Array en cadena y segundo, que compara dos cadenas. Así que este método es más rápido que el uso de la cadena .
Creo que siempre se deben almacenar grandes cantidades de datos en arreglos, no en objetos. Sin embargo, si utiliza objetos, también se pueden comparar parcialmente.
Así es cómo:
Comparando objetos:
He dicho anteriormente, que dos instancias de objetos nunca serán iguales, incluso si contienen los mismos datos en este momento:
({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666}) //false
Esto tiene una razón, ya que puede haber, por ejemplo, variables privadas dentro de los objetos.
Sin embargo, si solo usa la estructura de objetos para contener datos, la comparación es todavía posible:
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;
}
Sin embargo, recuerde que éste sirve para comparar datos como JSON, no instancias de clase y otras cosas. Si quieres comparar más objetos complicados, mira esta respuesta y es una función superlong .
Para que esto funcione con Array.equals
, debe editar un poco la función 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]) {
...
Hice una pequeña herramienta de prueba para ambas funciones .
Bonificación: Matrices anidadas con indexOf
y contains
Samy Bencherif ha preparado funciones útiles para el caso en el que está buscando un objeto específico en matrices anidadas, que están disponibles aquí: https://jsfiddle.net/SamyBencherif/8352y6yw/
Si bien esto solo funciona para matrices escalares (vea la nota a continuación), es breve:
array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})
Rr, en ECMAScript 6 / CoffeeScript / TypeScript con funciones de flecha:
array1.length === array2.length && array1.every((value, index) => value === array2[index])
(Nota: ''escalar'' aquí significa valores que se pueden comparar directamente usando ===
. Entonces: números, cadenas, objetos por referencia, funciones por referencia. Consulte la referencia de MDN para obtener más información sobre los operadores de comparación).
ACTUALIZAR
Por lo que leí de los comentarios, ordenar la matriz y comparar puede dar un resultado preciso:
array1.length === array2.length && array1.sort().every(function(value, index) { return value === array2.sort()[index]});
P.ej:
array1 = [2,3,1,4];
array2 = [1,2,3,4];
Entonces el código anterior daría true
Si son dos matrices de números o cadenas solamente, esta es una rápida de una línea
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
A pesar de que esto tiene muchas respuestas, una que creo que es de ayuda:
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
No se indica en la pregunta cómo se verá la estructura de la matriz, por lo que si está seguro de que no tendrá matrices anidadas ni objetos en su matriz (me pasó a mí, por eso llegué a esto). respuesta) el código anterior funcionará.
Lo que sucede es que usamos el operador de difusión (...) para concentrar ambas matrices, luego usamos Set para eliminar cualquier duplicado. Una vez que tengas eso, puedes comparar sus tamaños, si las tres matrices tienen el mismo tamaño, puedes irte.
Esta respuesta también ignora el orden de los elementos , como dije, la situación exacta me sucedió, así que tal vez alguien en la misma situación podría terminar aquí (como lo hice).
Edit1.
Respondiendo a la pregunta de Dmitry Grinko: "¿Por qué usaste el operador de propagación (...) aquí - ... ¿nuevo conjunto? No funciona"
Considere este código:
const arr1 = [ ''a'', ''b'' ]
const arr2 = [ ''a'', ''b'', ''c'' ]
const newArray = [ new Set( [...arr1, ...arr2] ) ]
console.log(newArray)
Obtendrás
[ Set { ''a'', ''b'', ''c'' } ]
Para trabajar con ese valor, necesitaría usar algunas propiedades del conjunto (consulte https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ). Por otro lado, cuando usas este código:
const arr1 = [ ''a'', ''b'' ]
const arr2 = [ ''a'', ''b'', ''c'' ]
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
console.log(newArray)
Obtendrás
[ ''a'', ''b'', ''c'' ]
Esa es la diferencia, el primero me daría un Set, también funcionaría, ya que podría obtener el tamaño de ese Set, pero el último me da el array que necesito, lo que es más directo a la resolución.
Aquí hay una versión de CoffeeScript, para aquellos que prefieren eso:
Array.prototype.equals = (array) ->
return false if not array # if the other array is a falsy value, return
return false if @length isnt array.length # compare lengths - can save a lot of time
for item, index in @
if item instanceof Array and array[index] instanceof Array # Check if we have nested arrays
if not item.equals(array[index]) # recurse into the nested arrays
return false
else if this[index] != array[index]
return false # Warning - two different object instances will never be equal: {x:20} != {x:20}
true
Todos los créditos van a @ tomas-zato.
Aquí hay una versión de Typescript:
//https://.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://.com/a/16436975/2589276
export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {
return JSON.stringify(a) === JSON.stringify(b)
}
Algunos casos de prueba para moca:
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)
})
Comparando 2 matrices:
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;
}
función de llamada
var isBool = compare(arr1.sort().join(),arr2.sort().join());
Elija cada uno de [a] y recorra todo de [b]: Resultado: 1, 5
var a = [1,4,5,9];
var b = [1,6,7,5];
for (i = 0; i < a.length; i++) {
for (z = 0; z < a.length; z++) {
if (a[i] === b[z]) {
console.log(b[z]); // if match > console.log it
}
}
}
Esta función compara dos matrices de forma arbitraria y dimesionalidad:
function equals(a1, a2) {
if (!Array.isArray(a1) || !Array.isArray(a2)) {
throw new Error("Arguments to function equals(a1, a2) must be arrays.");
}
if (a1.length !== a2.length) {
return false;
}
for (var i=0; i<a1.length; i++) {
if (Array.isArray(a1[i]) && Array.isArray(a2[i])) {
if (equals(a1[i], a2[i])) {
continue;
} else {
return false;
}
} else {
if (a1[i] !== a2[i]) {
return false;
}
}
}
return true;
}
Esto compara 2 matrices sin clasificar:
function areEqual(a, b) {
if ( a.length != b.length) {
return false;
}
return a.filter(function(i) {
return !b.includes(i);
}).length === 0;
}
Herer es mi solución:
/**
* 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 con cualquier estructura de datos anidada, y obviamente ignora los métodos de los objetos. Ni siquiera piense en extender Object.prototype con este método, cuando lo intenté una vez, jQuery se rompió;)
Para la mayoría de los arreglos, sigue siendo más rápido que la mayoría de las soluciones de serialización. Probablemente sea el método de comparación más rápido para matrices de registros de objetos.
La razón es que la identidad o el operador estricto (===) se compara con ninguna conversión de tipo, lo que significa que si ambos valores no tienen el mismo valor y el mismo tipo, no se considerarán iguales.
Eche un vistazo a este enlace, le sacará de dudas una manera fácil de entender cómo funciona el operador de identidad.
Si la matriz es simple y el orden es importante, estas dos líneas pueden ayudar
//Assume
var a = [''a'',''b'', ''c'']; var b = [''a'',''e'', ''c''];
if(a.length !== b.length) return false;
return !a.reduce(
function(prev,next,idx, arr){ return prev || next != b[idx] },false
);
Reduce los recorridos a través de uno de los matrices y devuelve ''falso'' si al menos un elemento de ''a'' no es igual al elemento de ''b'' Solo envuelve esto en función
esta secuencia de comandos compara objetos, matrices y matrices multidimensionales
function compare(a,b){
var primitive=[''string'',''number'',''boolean''];
if(primitive.indexOf(typeof a)!==-1 && primitive.indexOf(typeof a)===primitive.indexOf(typeof b))return a===b;
if(typeof a!==typeof b || a.length!==b.length)return false;
for(i in a){
if(!compare(a[i],b[i]))return false;
}
return true;
}
La primera línea comprueba si es un tipo primitivo. Si es así, compara los dos parámetros.
Si son objetos. itera sobre el Objeto y verifica cada elemento recursivamente.
Uso:
var a=[1,2,[1,2]];
var b=[1,2,[1,2]];
var isEqual=compare(a,b); //true
para una matriz de una sola dimensión simplemente puede usar:
arr1.sort().toString() == arr2.sort().toString()
Esto también se hará cargo de la matriz con el índice no coincidente.
En mi caso, los arreglos comparados contienen solo números y cadenas. Esta función le mostrará si los arreglos contienen los mismos elementos.
function are_arrs_match(arr1, arr2){
return arr1.sort().toString() === arr2.sort().toString()
}
¡Vamos a probarlo!
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
Extendiendo la idea de Tomáš Zato. Array.prototype.compare de Tomas debe ser de hecho llamado Array.prototype.compareIdentical.
Se pasa sobre
[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;
Pero falla en:
[[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]])
Aquí está la versión mejor (en mi opinión):
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;
}
Mi solución compara objetos, no matrices. Esto funcionaría de la misma manera que Tomáš, ya que las matrices son objetos, pero sin la advertencia:
Object.prototype.compare_to = function(comparable){
// Is the value being compared an object
if(comparable instanceof Object){
// Count the amount of properties in @comparable
var count_of_comparable = 0;
for(p in comparable) count_of_comparable++;
// Loop through all the properties in @this
for(property in this){
// Decrements once for every property in @this
count_of_comparable--;
// Prevents an infinite loop
if(property != "compare_to"){
// Is the property in @comparable
if(property in comparable){
// Is the property also an Object
if(this[property] instanceof Object){
// Compare the properties if yes
if(!(this[property].compare_to(comparable[property]))){
// Return false if the Object properties don''t match
return false;
}
// Are the values unequal
} else if(this[property] !== comparable[property]){
// Return false if they are unequal
return false;
}
} else {
// Return false if the property is not in the object being compared
return false;
}
}
}
} else {
// Return false if the value is anything other than an object
return false;
}
// Return true if their are as many properties in the comparable object as @this
return count_of_comparable == 0;
}
Espero que esto te ayude a ti oa alguien más en busca de una respuesta.
Podríamos hacer esto de manera 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
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ? array.push(collection[i]) : null
Así es como lo hice.
function compareArrays(arrayA, arrayB) {
if (arrayA.length != arrayB.length) return true;
for (i = 0; i < arrayA.length; i++)
if (arrayB.indexOf(arrayA[i]) == -1) {
return true;
}
}
for (i = 0; i < arrayB.length; i++) {
if (arrayA.indexOf(arrayB[i]) == -1) {
return true;
}
}
return false;
}
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);
////// O ///////
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)