repetidos - ordenar array multidimensional javascript
Comparando matrices de objetos en JavaScript (7)
Quiero comparar 2 matrices de objetos en código JavaScript. Los objetos tienen 8 propiedades en total, pero cada objeto no tendrá un valor para cada uno, y las matrices nunca serán mayores de 8 elementos cada una, así que tal vez el método de fuerza bruta para atravesar cada una y luego mirar los valores de la 8 propiedades es la manera más fácil de hacer lo que quiero hacer, pero antes de implementarlo, quería ver si alguien tenía una solución más elegante. ¿Alguna idea?
Aquí está mi intento, usando el módulo de afirmación de Node + npm package object-hash .
Supongo que le gustaría comprobar si dos matrices contienen los mismos objetos, incluso si esos objetos se ordenan de manera diferente entre las dos matrices.
var assert = require(''assert'');
var hash = require(''object-hash'');
var obj1 = {a: 1, b: 2, c: 333},
obj2 = {b: 2, a: 1, c: 444},
obj3 = {b: "AAA", c: 555},
obj4 = {c: 555, b: "AAA"};
var array1 = [obj1, obj2, obj3, obj4];
var array2 = [obj3, obj2, obj4, obj1]; // [obj3, obj3, obj2, obj1] should work as well
// calling assert.deepEquals(array1, array2) at this point FAILS (throws an AssertionError)
// even if array1 and array2 contain the same objects in different order,
// because array1[0].c !== array2[0].c
// sort objects in arrays by their hashes, so that if the arrays are identical,
// their objects can be compared in the same order, one by one
var array1 = sortArrayOnHash(array1);
var array2 = sortArrayOnHash(array2);
// then, this should output "PASS"
try {
assert.deepEqual(array1, array2);
console.log("PASS");
} catch (e) {
console.log("FAIL");
console.log(e);
}
// You could define as well something like Array.prototype.sortOnHash()...
function sortArrayOnHash(array) {
return array.sort(function(a, b) {
return hash(a) > hash(b);
});
}
EDITAR: No se puede sobrecargar a los operadores en implementaciones actuales y comunes basadas en navegador de intérpretes de JavaScript.
Para responder a la pregunta original, una manera en que podría hacer esto, y tener en cuenta que es un truco, simplemente serialice las dos matrices en JSON y luego compare las dos cadenas JSON. Eso simplemente te diría si las matrices son diferentes, obviamente podrías hacer esto a cada uno de los objetos dentro de las matrices y ver cuáles son diferentes.
Otra opción es usar una biblioteca que tenga buenas instalaciones para comparar objetos: uso y recomiendo MochiKit .
EDITAR: La respuesta dada por kamens también merece consideración, ya que una sola función para comparar dos objetos dados sería mucho más pequeña que cualquier biblioteca para hacer lo que sugiero (aunque mi sugerencia ciertamente funcionaría lo suficientemente bien).
Aquí hay una implementación ingenua que puede hacer lo suficiente para usted: tenga en cuenta que existen posibles problemas con esta implementación:
function objectsAreSame(x, y) {
var objectsAreSame = true;
for(var propertyName in x) {
if(x[propertyName] !== y[propertyName]) {
objectsAreSame = false;
break;
}
}
return objectsAreSame;
}
La suposición es que ambos objetos tienen la misma lista exacta de propiedades.
Ah, y probablemente sea obvio que, para bien o para mal, pertenezco al campo de un solo punto de retorno. :)
He trabajado un poco en un algoritmo simple para comparar el contenido de dos objetos y devolver una lista inteligible de diferencia. Pensé que compartiría. Toma prestadas algunas ideas para jQuery, a saber, la implementación de la función del map
y la comprobación del tipo de objeto y matriz.
Devuelve una lista de "objetos diff", que son matrices con la información diff. Es muy sencillo.
Aquí está:
// compare contents of two objects and return a list of differences
// returns an array where each element is also an array in the form:
// [accessor, diffType, leftValue, rightValue ]
//
// diffType is one of the following:
// value: when primitive values at that index are different
// undefined: when values in that index exist in one object but don''t in
// another; one of the values is always undefined
// null: when a value in that index is null or undefined; values are
// expressed as boolean values, indicated wheter they were nulls
// type: when values in that index are of different types; values are
// expressed as types
// length: when arrays in that index are of different length; values are
// the lengths of the arrays
//
function DiffObjects(o1, o2) {
// choose a map() impl.
// you may use $.map from jQuery if you wish
var map = Array.prototype.map?
function(a) { return Array.prototype.map.apply(a, Array.prototype.slice.call(arguments, 1)); } :
function(a, f) {
var ret = new Array(a.length), value;
for ( var i = 0, length = a.length; i < length; i++ )
ret[i] = f(a[i], i);
return ret.concat();
};
// shorthand for push impl.
var push = Array.prototype.push;
// check for null/undefined values
if ((o1 == null) || (o2 == null)) {
if (o1 != o2)
return [["", "null", o1!=null, o2!=null]];
return undefined; // both null
}
// compare types
if ((o1.constructor != o2.constructor) ||
(typeof o1 != typeof o2)) {
return [["", "type", Object.prototype.toString.call(o1), Object.prototype.toString.call(o2) ]]; // different type
}
// compare arrays
if (Object.prototype.toString.call(o1) == "[object Array]") {
if (o1.length != o2.length) {
return [["", "length", o1.length, o2.length]]; // different length
}
var diff =[];
for (var i=0; i<o1.length; i++) {
// per element nested diff
var innerDiff = DiffObjects(o1[i], o2[i]);
if (innerDiff) { // o1[i] != o2[i]
// merge diff array into parent''s while including parent object name ([i])
push.apply(diff, map(innerDiff, function(o, j) { o[0]="[" + i + "]" + o[0]; return o; }));
}
}
// if any differences were found, return them
if (diff.length)
return diff;
// return nothing if arrays equal
return undefined;
}
// compare object trees
if (Object.prototype.toString.call(o1) == "[object Object]") {
var diff =[];
// check all props in o1
for (var prop in o1) {
// the double check in o1 is because in V8 objects remember keys set to undefined
if ((typeof o2[prop] == "undefined") && (typeof o1[prop] != "undefined")) {
// prop exists in o1 but not in o2
diff.push(["[" + prop + "]", "undefined", o1[prop], undefined]); // prop exists in o1 but not in o2
}
else {
// per element nested diff
var innerDiff = DiffObjects(o1[prop], o2[prop]);
if (innerDiff) { // o1[prop] != o2[prop]
// merge diff array into parent''s while including parent object name ([prop])
push.apply(diff, map(innerDiff, function(o, j) { o[0]="[" + prop + "]" + o[0]; return o; }));
}
}
}
for (var prop in o2) {
// the double check in o2 is because in V8 objects remember keys set to undefined
if ((typeof o1[prop] == "undefined") && (typeof o2[prop] != "undefined")) {
// prop exists in o2 but not in o1
diff.push(["[" + prop + "]", "undefined", undefined, o2[prop]]); // prop exists in o2 but not in o1
}
}
// if any differences were found, return them
if (diff.length)
return diff;
// return nothing if objects equal
return undefined;
}
// if same type and not null or objects or arrays
// perform primitive value comparison
if (o1 != o2)
return [["", "value", o1, o2]];
// return nothing if values are equal
return undefined;
}
Honestamente, con 8 objetos máximo y 8 propiedades máximo por objeto, la mejor opción es atravesar cada objeto y hacer las comparaciones directamente. Será rápido y será fácil.
Si va a utilizar este tipo de comparaciones a menudo, entonces estoy de acuerdo con Jason sobre la serialización JSON ... pero de lo contrario no hay necesidad de ralentizar su aplicación con una nueva biblioteca o código de serialización JSON.
La función objectsAreSame
mencionada en @ La respuesta de JasonBunting funciona bien para mí. Sin embargo, hay un pequeño problema: si x[propertyName]
y y[propertyName]
son objetos ( typeof x[propertyName] == ''object''
), deberá llamar a la función recursivamente para compararlos.
Por favor, pruebe este:
function used_to_compare_two_arrays(a, b)
{
// This block will make the array of indexed that array b contains a elements
var c = a.filter(function(value, index, obj) {
return b.indexOf(value) > -1;
});
// This is used for making comparison that both have same length if no condition go wrong
if (c.length !== a.length) {
return 0;
} else{
return 1;
}
}
Sé que esta es una vieja pregunta y las respuestas proporcionadas funcionan bien ... pero esto es un poco más corto y no requiere ninguna biblioteca adicional (es decir, JSON):
function arraysAreEqual(ary1,ary2){
return (ary1.join('''') == ary2.join(''''));
}