2008-08-25 33 views
38

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?Comparación de matrices de objetos en JavaScript

Respuesta

35

EDITAR: No se puede sobrecargar a los operadores en las implementaciones actuales y comunes basadas en navegador de intérpretes de JavaScript.

Para responder a la pregunta original, una forma en que podría hacer esto, y tener en cuenta, esto es un poco complicado, simplemente serialize the two arrays to JSON y luego compare las dos cadenas JSON. Eso simplemente le diría si las matrices son diferentes, obviamente, podría hacer esto en cada de los objetos dentro de las matrices, así como para ver cuáles eran diferentes.

Otra opción es utilizar una biblioteca que tenga algunas buenas instalaciones para comparar objetos - Yo uso y recomiendo MochiKit.


EDIT:The answer kamens gave merece consideración también, ya que una sola función para comparar dos objetos dados sería mucho más pequeño que cualquier biblioteca para hacer lo que sugieren (aunque mi sugerencia sería ciertamente funcionar lo suficientemente bien).

Aquí es una implemenation ingenuo que pueden hacer lo suficiente para usted - tenga en cuenta que hay problemas potenciales 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 campamento de un solo punto de retorno. :)

+1

Solo para señalar la limitación: parece que fallará al comparar objetos que contienen objetos. (Y como mencionas, fallará cuando los dos objetos no tengan "la misma lista exacta de propiedades", ya que 'y' puede ser un superconjunto de 'x'. –

+4

Una advertencia sobre la sugerencia de serialización JSON es que si comparas objetos (no matrices) y no te importa el orden (por ejemplo, claves con nombre, no una matriz numérica), bueno, entonces la serialización JSON no funcionará. –

+0

@AlanH. ¿Quieres decir 'JSON. stringify' debería funcionar para comparar dos matrices que no son Object (p. ej. Number, String), así como dos matrices Object, pero no para comparar dos Objects? En caso afirmativo, ¿por qué? esp. en el caso de comparar dos matrices Object? – zyxue

10

Honestamente, con 8 objetos máximo y 8 propiedades máximo por objeto, su 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.

+15

"... Estoy de acuerdo con Jason sobre JSON ..." +1 solo por eso! ;-) – Cerebrus

0

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.

7

He trabajado un poco en un algoritmo simple para comparar el contenido de dos objetos y devolver una lista inteligible de la diferencia. Pensé que compartiría. Toma prestadas algunas ideas para jQuery, a saber, la implementación de la función map y la comprobación del tipo de objetos y matrices.

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; 
} 
14

Sé que esto es una vieja pregunta y las respuestas proporcionadas trabajo fino ...pero esto es un poco más corto y no requiere librerías adicionales (es decir, JSON):

function arraysAreEqual(ary1,ary2){ 
    return (ary1.join('') == ary2.join('')); 
} 
+8

El OP quería unir matrices de objetos. Esto solo funciona para arreglos de escalares. –

+0

bastante bien Jonathan. Me lo perdí. – jwood

+6

También es frágil. Si: 'a = [" 1,2 "], b = [" 1 "," 2 "]' luego un 'join()' en los dos arreglos diferentes dará como resultado ''1,2'' –

0

Por favor, intente éste:

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; 
    } 
} 
0

Aquí es mi intento, utilizando Node's assert module + NPM paquete 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); 
    }); 
}