Utilizzo di jQuery per confrontare due array di oggetti Javascript


93

Ho due array di oggetti JavaScript che vorrei confrontare per vedere se sono gli stessi. Gli oggetti potrebbero non (e molto probabilmente non lo saranno) essere nello stesso ordine in ogni matrice. Ciascun array non dovrebbe avere più di 10 oggetti. Pensavo che jQuery potesse avere un'elegante soluzione a questo problema, ma non sono riuscito a trovare molto online.

So che una $.each(array, function(){})soluzione nidificata bruta potrebbe funzionare, ma c'è qualche funzione incorporata di cui non sono a conoscenza?

Grazie.

Risposte:


277

C'è un modo semplice ...

$(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0

Se quanto sopra restituisce true, entrambi gli array sono uguali anche se gli elementi sono in ordine diverso.

NOTA: funziona solo per le versioni jquery <3.0.0 quando si utilizzano oggetti JSON


12
+1, tuttavia è vero quando si confronta un array con un oggetto che contiene le stesse proprietà, ad es[0,1] == {0:0,1:1,length=2}
David Hellsing,

4
perché $(arr1).not(arr2).length == 0non è abbastanza?
Alexxus

10
@ Alexxus, hai bisogno di entrambi i confronti perché notè una funzione di filtro, non una funzione di uguaglianza. Provalo con [1,2]e [1]. In un ordine, otterrai []e in un altro, otterrai [2].
Noyo

3
Nota che se hai duplicati in un array, questo restituirà true. Quindi qualcosa come: "[1,1,2,2,3,3] == [1,2,3]" è vero.
Philll_t

3
jQuery notnon funziona più con oggetti generici a partire dalla versione 3.0.0-rc1. Vedi github.com/jquery/jquery/issues/3147
Marc-André Lafortune

35

Anche stavo cercando questo oggi e ho trovato: http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD

Non so se sia una buona soluzione anche se menzionano alcune considerazioni sulle prestazioni prese in considerazione.

Mi piace l'idea di un metodo di supporto jQuery. @David preferirei vedere il tuo metodo di confronto funzionare come:

jQuery.compare(a, b)

Non ha senso per me fare:

$(a).compare(b)

dove aeb sono array. Normalmente quando $ (qualcosa) si passa una stringa di selettore per lavorare con gli elementi DOM.

Anche per quanto riguarda l'ordinamento e il "caching" degli array ordinati:

  • Non penso che l'ordinamento una volta all'inizio del metodo invece che ogni volta attraverso il ciclo sia "memorizzazione nella cache". L'ordinamento verrà comunque eseguito ogni volta che si chiama compare (b). È solo semantica, ma ...
  • for (var i = 0; t [i]; i ++) { ... questo ciclo termina presto se il tuo array t contiene un valore falso da qualche parte, quindi $ ([1, 2, 3, 4]). compare ( [1, false, 2, 3]) restituisce true !
  • Ancora più importante, il metodo array sort () ordina l'array in posizione , quindi var b = t.sort () ... non crea una copia ordinata dell'array originale, ordina l' array originale e assegna anche un riferimento a esso in b . Non credo che il metodo di confronto dovrebbe avere effetti collaterali.

Sembra che quello che dobbiamo fare sia copiare gli array prima di lavorarci. La migliore risposta che sono riuscito a trovare su come farlo in modo jQuery è stata nientemeno che da John Resig qui su SO! Qual è il modo più efficiente per clonare in profondità un oggetto in JavaScript? (vedere i commenti sulla sua risposta per la versione array della ricetta per la clonazione degli oggetti)

In tal caso penso che il codice per esso sarebbe:

jQuery.extend({
    compare: function (arrayA, arrayB) {
        if (arrayA.length != arrayB.length) { return false; }
        // sort modifies original array
        // (which are passed by reference to our method!)
        // so clone the arrays before sorting
        var a = jQuery.extend(true, [], arrayA);
        var b = jQuery.extend(true, [], arrayB);
        a.sort(); 
        b.sort();
        for (var i = 0, l = a.length; i < l; i++) {
            if (a[i] !== b[i]) { 
                return false;
            }
        }
        return true;
    }
});

var a = [1, 2, 3];
var b = [2, 3, 4];
var c = [3, 4, 2];

jQuery.compare(a, b);
// false

jQuery.compare(b, c);
// true

// c is still unsorted [3, 4, 2]

2
in realtà probabilmente chiamerei questo metodo 'arrayCompare' piuttosto che 'compare' poiché è l'unica cosa su cui è progettato per funzionare ...
Anentropic

Perfetto davvero. Molte grazie.
dimitarvp

14

Il mio approccio era abbastanza diverso: ho appiattito entrambe le raccolte utilizzando JSON.stringify e ho utilizzato un confronto di stringhe normale per verificare l'uguaglianza.

Cioè

var arr1 = [
             {Col: 'a', Val: 1}, 
             {Col: 'b', Val: 2}, 
             {Col: 'c', Val: 3}
           ];

var arr2 = [
             {Col: 'x', Val: 24}, 
             {Col: 'y', Val: 25}, 
             {Col: 'z', Val: 26}
           ];

if(JSON.stringify(arr1) == JSON.stringify(arr2)){
    alert('Collections are equal');
}else{
    alert('Collections are not equal');
}

NB: Si prega di notare che il suo metodo presume che entrambe le raccolte siano ordinate in modo simile, in caso contrario, si otterrebbe un risultato falso!


1
Avevo bisogno di un metodo semplice per confrontare gli array nei miei unit test, assicurando lo stesso ordine per i due array. È molto carino, grazie.
aymericbeaumet

Grazie per
avermi

12

Converti entrambi gli array in stringhe e confronta

if (JSON.stringify(array1) == JSON.stringify(array2))
{
    // your code here
}

1
Sembra buono per confrontare array annidati e quando l'ordine è importante.
Pierre de LESPINAY

3

Ho trovato questa discussione perché avevo bisogno di un modo per confrontare in profondità array e oggetti. Usando gli esempi qui, ho trovato quanto segue (suddiviso in 3 metodi per chiarezza):

jQuery.extend({
    compare : function (a,b) {
        var obj_str = '[object Object]',
            arr_str = '[object Array]',
            a_type  = Object.prototype.toString.apply(a),
            b_type  = Object.prototype.toString.apply(b);

            if ( a_type !== b_type) { return false; }
            else if (a_type === obj_str) {
                return $.compareObject(a,b);
            }
            else if (a_type === arr_str) {
                return $.compareArray(a,b);
            }
            return (a === b);
        }
});

jQuery.extend({
    compareArray: function (arrayA, arrayB) {
        var a,b,i,a_type,b_type;
        // References to each other?
        if (arrayA === arrayB) { return true;}

        if (arrayA.length != arrayB.length) { return false; }
        // sort modifies original array
        // (which are passed by reference to our method!)
        // so clone the arrays before sorting
        a = jQuery.extend(true, [], arrayA);
        b = jQuery.extend(true, [], arrayB);
        a.sort(); 
        b.sort();
        for (i = 0, l = a.length; i < l; i+=1) {
            a_type = Object.prototype.toString.apply(a[i]);
            b_type = Object.prototype.toString.apply(b[i]);

            if (a_type !== b_type) {
                return false;
            }

            if ($.compare(a[i],b[i]) === false) {
                return false;
            }
        }
        return true;
    }
});

jQuery.extend({
    compareObject : function(objA,objB) {

        var i,a_type,b_type;

        // Compare if they are references to each other 
        if (objA === objB) { return true;}

        if (Object.keys(objA).length !== Object.keys(objB).length) { return false;}
        for (i in objA) {
            if (objA.hasOwnProperty(i)) {
                if (typeof objB[i] === 'undefined') {
                    return false;
                }
                else {
                    a_type = Object.prototype.toString.apply(objA[i]);
                    b_type = Object.prototype.toString.apply(objB[i]);

                    if (a_type !== b_type) {
                        return false; 
                    }
                }
            }
            if ($.compare(objA[i],objB[i]) === false){
                return false;
            }
        }
        return true;
    }
});

Test

var a={a : {a : 1, b: 2}},
    b={a : {a : 1, b: 2}},
    c={a : {a : 1, b: 3}},
    d=[1,2,3],
    e=[2,1,3];

console.debug('a and b = ' + $.compare(a,b)); // a and b = true
console.debug('b and b = ' + $.compare(b,b)); // b and b = true
console.debug('b and c = ' + $.compare(b,c)); // b and c = false
console.debug('c and d = ' + $.compare(c,d)); // c and d = false
console.debug('d and e = ' + $.compare(d,e)); // d and e = true

3

Nel mio caso gli array confrontati contengono solo numeri e stringhe . Questa soluzione ha funzionato per me:

function are_arrs_equal(arr1, arr2){
    return arr1.sort().toString() === arr2.sort().toString()
}

Proviamolo!

arr1 = [1, 2, 3, 'nik']
arr2 = ['nik', 3, 1, 2]
arr3 = [1, 2, 5]

console.log (are_arrs_equal(arr1, arr2)) //true
console.log (are_arrs_equal(arr1, arr3)) //false

1

Non penso che ci sia un buon modo "jQuery" per farlo, ma se hai bisogno di efficienza, mappa uno degli array con una certa chiave (uno dei campi oggetto univoci), e poi fai il confronto scorrendo l'altro array e confrontandoli con la mappa, o array associativo, che hai appena creato.

Se l'efficienza non è un problema, confronta semplicemente ogni oggetto in A con ogni oggetto in B. Finché | A | e | B | sei piccolo, dovresti stare bene.


@Stefan, grazie per la rapida risposta. Puoi pubblicare un codice di esempio per la tua idea di mappatura? Grazie.
MegaMatt

1

Bene, se vuoi confrontare solo il contenuto degli array, c'è un'utile funzione jQuery $ .inArray ()

var arr = [11, "String #1", 14, "String #2"];
var arr_true = ["String #1", 14, "String #2", 11]; // contents are the same as arr
var arr_false = ["String #1", 14, "String #2", 16]; // contents differ

function test(arr_1, arr_2) {
    var equal = arr_1.length == arr_2.length; // if array sizes mismatches, then we assume, that they are not equal
    if (equal) {
        $.each(arr_1, function (foo, val) {
            if (!equal) return false;
            if ($.inArray(val, arr_2) == -1) {
                equal = false;
            } else {
                equal = true;
            }
        });
    }
    return equal;
}

alert('Array contents are the same? ' + test(arr, arr_true)); //- returns true
alert('Array contents are the same? ' + test(arr, arr_false)); //- returns false

Buona soluzione, ma non sono sicuro che questo sia il motivo per cui gli array hanno gli stessi elementi, ma in un ordine diverso.
MegaMatt

Puoi muoverti se (! Uguale) restituisce false; fino alla fine di $ .each per evitare di attivare nuovamente la funzione. E puoi tornare uguale; per evitare un confronto.
Matt

1

Cambia l'array in stringa e confronta

var arr = [1,2,3], 
arr2 = [1,2,3]; 
console.log(arr.toString() === arr2.toString());

1

Il bel liner di Sudhakar R come metodo globale jQuery.

/**
 * Compare two arrays if they are equal even if they have different order.
 *
 * @link https://stackoverflow.com/a/7726509
 */
jQuery.extend({
  /**
   * @param {array} a
   *   First array to compare.
   * @param {array} b
   *   Second array to compare.
   * @return {boolean}
   *   True if both arrays are equal, otherwise false.
   */
  arrayCompare: function (a, b) {
    return $(a).not(b).get().length === 0 && $(b).not(a).get().length === 0;
  }
});

0

Ho anche trovato questo quando cercavo di fare alcuni confronti di array con jQuery. Nel mio caso avevo stringhe che sapevo essere array:

var needle = 'apple orange';
var haystack = 'kiwi orange banana apple plum';

Ma mi importava se fosse una corrispondenza completa o solo parziale, quindi ho usato qualcosa come il seguente, basato sulla risposta di Sudhakar R:

function compareStrings( needle, haystack ){
  var needleArr = needle.split(" "),
    haystackArr = haystack.split(" "),
    compare = $(haystackArr).not(needleArr).get().length;

  if( compare == 0 ){
    return 'all';
  } else if ( compare == haystackArr.length  ) {
    return 'none';
  } else {
    return 'partial';
  }
}

0

Se i duplicati contano in modo tale che [1, 1, 2]non dovrebbero essere uguali [2, 1]ma dovrebbero essere uguali [1, 2, 1], ecco una soluzione per il conteggio dei riferimenti:

  const arrayContentsEqual = (arrayA, arrayB) => {
    if (arrayA.length !== arrayB.length) {
      return false}

    const refCount = (function() {
      const refCountMap = {};
      const refCountFn = (elt, count) => {
          refCountMap[elt] = (refCountMap[elt] || 0) + count}
      refCountFn.isZero = () => {
        for (let elt in refCountMap) {
          if (refCountMap[elt] !== 0) {
            return false}}
        return true}
      return refCountFn})()

    arrayB.map(eltB => refCount(eltB, 1));
    arrayA.map(eltA => refCount(eltA, -1));
    return refCount.isZero()}

Ecco il violino con cui giocare .


0

var arr1 = [
             {name: 'a', Val: 1}, 
             {name: 'b', Val: 2}, 
             {name: 'c', Val: 3}
           ];

var arr2 = [
             {name: 'c', Val: 3},
             {name: 'x', Val: 4}, 
             {name: 'y', Val: 5}, 
             {name: 'z', Val: 6}
           ];
var _isEqual = _.intersectionWith(arr1, arr2, _.isEqual);// common in both array
var _difference1 = _.differenceWith(arr1, arr2, _.isEqual);//difference from array1 
var _difference2 = _.differenceWith(arr2, arr1, _.isEqual);//difference from array2 
console.log(_isEqual);// common in both array
console.log(_difference1);//difference from array1 
console.log(_difference2);//difference from array2 
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>


-3

Prova questo

function check(c,d){
  var a = c, b = d,flg = 0;
  if(a.length == b.length) 
  { 
     for(var i=0;i<a.length;i++) 
           a[i] != b[i] ? flg++ : 0; 
  } 
  else  
  { 
     flg = 1; 
  } 
  return flg = 0;
}

Ciò modifica sia a che b e confronta solo il primo elemento. wtf.
ScottJ

1
@ScottJ Mr.AH La domanda è confrontare due array .. Dopo l'ordinamento, se entrambi gli array sono uguali a [0] == b [0]. wtf bah.
Eccezione

2
Temo di non sapere cosa significhi AH e Google non è stato di aiuto. Ma se il mio commento era così fuori base, perché questo codice è stato completamente riscritto il 21 febbraio?
ScottJ

@ScottJ Molto probabilmente AH === wtf
Eccezione
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.