2008-08-25 24 views
38

Desidero confrontare 2 matrici di oggetti nel codice JavaScript. Gli oggetti hanno 8 proprietà totali, ma ogni oggetto non avrà un valore per ciascuno, e gli array non saranno mai più grandi di 8 elementi ciascuno, quindi forse il metodo di forza bruta di attraversare ciascuno e quindi guardando i valori del 8 proprietà è il modo più semplice per fare ciò che voglio fare, ma prima di implementarle volevo vedere se qualcuno avesse una soluzione più elegante. qualche idea?Confronto di matrici di oggetti in JavaScript

risposta

35

MODIFICA: non è possibile sovraccaricare gli operatori nelle attuali e comuni implementazioni basate su browser di interpreti JavaScript.

Per rispondere alla domanda iniziale, un modo per farlo, e sia chiaro, questo è un po 'un trucco, semplicemente serialize the two arrays to JSON e quindi confrontare le due stringhe JSON. Questo ti dirà semplicemente se gli array sono diversi, ovviamente puoi farlo a ogni degli oggetti all'interno degli array e vedere quali erano diversi.

Un'altra opzione consiste nell'utilizzare una libreria che ha alcune buone funzionalità per confrontare gli oggetti: io uso e raccomando MochiKit.


EDIT:The answer kamens gave merita considerazione pure, dal momento che una singola funzione per confrontare due oggetti dati sarebbe molto più piccolo di qualsiasi libreria per fare quello che ti suggerisco (anche se il mio suggerimento sarebbe certamente lavorare abbastanza bene).

Ecco un implemenation ingenuo che può fare proprio abbastanza per voi - essere consapevoli che ci sono potenziali problemi con questa implementazione:

function objectsAreSame(x, y) { 
    var objectsAreSame = true; 
    for(var propertyName in x) { 
     if(x[propertyName] !== y[propertyName]) { 
     objectsAreSame = false; 
     break; 
     } 
    } 
    return objectsAreSame; 
} 

Il presupposto è che entrambi gli oggetti hanno la stessa lista esatta dei proprietà.

Oh, ed è probabilmente ovvio che, nel bene o nel male, appartengo al campo di un solo punto di ritorno. :)

+1

Solo per evidenziare la limitazione: sembra che non riuscirà quando si confrontano oggetti che contengono oggetti. (E come dici tu, fallirà quando i due oggetti non hanno "lo stesso elenco esatto di proprietà", poiché 'y' può essere un super-set di' x'. –

+4

Un avvertimento riguardo il suggerimento di serializzazione JSON è che se si confrontano gli oggetti (non gli array) e non si preoccupano dell'ordine (ad es. le chiavi nominate, non un array numerico), beh, allora la serializzazione JSON non funzionerà –

+0

@AlanH. stringify' dovrebbe funzionare per confrontare due matrici non Object (ad esempio Number, String) e due matrici Object, ma non per confrontare due oggetti? Se sì, perché? specialmente nel caso di confronto di due matrici Object? – zyxue

10

Onestamente, con 8 oggetti max e 8 proprietà max per oggetto, la soluzione migliore è semplicemente attraversare ogni oggetto e fare i confronti direttamente. Sarà veloce e sarà facile.

Se si utilizzano spesso questi tipi di confronti, sono d'accordo con Jason sulla serializzazione JSON ... ma altrimenti non è necessario rallentare l'app con una nuova libreria o codice di serializzazione JSON.

+15

"... Sono d'accordo con Jason su JSON ..." +1 solo per quello! ;-) – Cerebrus

0

La funzione objectsAreSame menzionata nella risposta di @ JasonBunting funziona correttamente per me. Tuttavia, c'è un piccolo problema: se x[propertyName] e y[propertyName] sono oggetti (typeof x[propertyName] == 'object'), è necessario chiamare la funzione in modo ricorsivo per confrontarli.

7

Ho lavorato un po 'su un semplice algoritmo per confrontare il contenuto di due oggetti e restituire un elenco comprensibile di differenza. Ho pensato di condividere. Prende in prestito alcune idee per jQuery, ovvero l'implementazione della funzione map e il controllo del tipo di oggetto e array.

Restituisce un elenco di "oggetti diff", che sono matrici con le informazioni di diff. È molto semplice.

Eccolo:

// 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

So che questa è una vecchia questione e le risposte fornite funzionano bene ...ma questo è un po 'più corta e non richiede nessuna libreria aggiuntiva (cioè JSON):

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

L'OP voleva unire matrici di oggetti. Funziona solo per gli array di scalari. –

+0

giustamente Jonathan. Ho perso questo. – jwood

+6

È anche fragile. Se: 'a = [" 1,2 "], b = [" 1 "," 2 "]' allora un 'join()' sui due diversi array risulterà in ''1,2'' –

0

Si prega di provare questo:

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

Ecco il mio tentativo, utilizzando Node's assert module + NPM pacchetto object-hash.

Suppongo che si desideri controllare se due array contengono gli stessi oggetti, anche se tali oggetti sono ordinati in modo diverso tra i due array.

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); 
    }); 
} 
Problemi correlati