Verwenden von jQuery zum Vergleichen von zwei Arrays von Javascript-Objekten

93

Ich habe zwei Arrays von JavaScript-Objekten, die ich vergleichen möchte, um festzustellen, ob sie identisch sind. Die Objekte befinden sich möglicherweise nicht in jedem Array in derselben Reihenfolge (und werden dies höchstwahrscheinlich auch nicht tun). Jedes Array sollte nicht mehr als 10 Objekte enthalten. Ich dachte, jQuery könnte eine elegante Lösung für dieses Problem haben, aber ich konnte online nicht viel finden.

Ich weiß, dass eine brutal verschachtelte $.each(array, function(){})Lösung funktionieren könnte, aber gibt es eine integrierte Funktion, die mir nicht bekannt ist?

Vielen Dank.

MegaMatt
quelle

Antworten:

277

Es gibt einen einfachen Weg ...

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

Wenn das oben Gesagte true zurückgibt, sind beide Arrays gleich, auch wenn die Elemente in unterschiedlicher Reihenfolge vorliegen.

HINWEIS: Dies funktioniert nur für JQuery-Versionen <3.0.0, wenn JSON-Objekte verwendet werden

suDocker
quelle
12
+1, aber es ist gleich wahr , wenn Sie ein Array mit einem Objekt vergleichen , die die gleichen Eigenschaften enthalten, f.ex[0,1] == {0:0,1:1,length=2}
David Hellsing
4
warum $(arr1).not(arr2).length == 0ist nicht genug
Alexxus
10
@Alexxus, Sie benötigen beide Vergleiche, da notes sich um eine Filterfunktion und nicht um eine Gleichheitsfunktion handelt. Probieren Sie es mit [1,2]und [1]. In einer Reihenfolge erhalten Sie []und in einer anderen erhalten Sie [2].
Noyo
3
Beachten Sie, dass bei Duplikaten in einem Array true zurückgegeben wird. Also so etwas wie: "[1,1,2,2,3,3] == [1,2,3]" ist wahr.
Philll_t
3
jQuery notfunktioniert ab 3.0.0-rc1 nicht mehr mit generischen Objekten. Siehe github.com/jquery/jquery/issues/3147
Marc-André Lafortune
35

Ich habe heute auch danach gesucht und Folgendes gefunden: http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD

Ich weiß nicht, ob dies eine gute Lösung ist, obwohl einige Leistungsaspekte berücksichtigt werden.

Ich mag die Idee einer jQuery-Hilfsmethode. @ David Ich würde lieber sehen, dass Ihre Vergleichsmethode wie folgt funktioniert:

jQuery.compare(a, b)

Es macht für mich keinen Sinn, Folgendes zu tun:

$(a).compare(b)

wobei a und b Arrays sind. Normalerweise würden Sie beim $ (etwas) eine Auswahlzeichenfolge übergeben, um mit DOM-Elementen zu arbeiten.

Auch in Bezug auf das Sortieren und "Zwischenspeichern" der sortierten Arrays:

  • Ich denke nicht, dass das einmalige Sortieren zu Beginn der Methode statt jedes Mal durch die Schleife 'Caching' ist. Die Sortierung erfolgt weiterhin jedes Mal, wenn Sie compare (b) aufrufen. Das ist nur Semantik, aber ...
  • for (var i = 0; t [i]; i ++) { ... diese Schleife wird vorzeitig beendet, wenn Ihr t- Array irgendwo einen falschen Wert enthält, also $ ([1, 2, 3, 4]). compare ( [1, false, 2, 3]) gibt true zurück !
  • Noch wichtiger ist, dass die Array sort () -Methode das Array an Ort und Stelle sortiert. Wenn Sie also var b = t.sort () ... ausführen, wird keine sortierte Kopie des ursprünglichen Arrays erstellt, sondern das ursprüngliche Array sortiert und auch ein Verweis auf zugewiesen es in b . Ich denke nicht, dass die Vergleichsmethode Nebenwirkungen haben sollte.

Es scheint, dass wir die Arrays kopieren müssen, bevor wir daran arbeiten. Die beste Antwort, die ich finden konnte, um das auf jQuery-Weise zu tun, war von niemand anderem als John Resig hier auf SO! Was ist der effizienteste Weg, um ein Objekt in JavaScript tief zu klonen? (Siehe Kommentare zu seiner Antwort für die Array-Version des Objektklonrezepts)

In diesem Fall denke ich, wäre der Code dafür:

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]
Anentropisch
quelle
2
Eigentlich würde ich diese Methode wahrscheinlich eher "arrayCompare" als "compare" nennen, da dies das einzige ist, an dem sie arbeiten soll ...
Anentropic
Genau richtig. Vielen Dank.
dimitarvp
14

Mein Ansatz war ganz anders: Ich habe beide Sammlungen mit JSON.stringify abgeflacht und einen normalen Zeichenfolgenvergleich verwendet, um die Gleichheit zu überprüfen.

Dh

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: Bitte beachten Sie, dass seine Methode davon ausgeht, dass beide Sammlungen auf ähnliche Weise sortiert sind. Andernfalls würden Sie ein falsches Ergebnis erhalten!

Kwex
quelle
1
Ich brauchte eine einfache Methode, um Arrays in meinen Unit-Tests zu vergleichen und die gleiche Reihenfolge für die beiden Arrays sicherzustellen. Es ist sehr schön, danke.
Aymericbeaumet
Danke, dass du meinen Tag gerettet hast
Sourabh Kumar Sharma
12

Konvertieren Sie beide Arrays in Zeichenfolgen und vergleichen Sie sie

if (JSON.stringify(array1) == JSON.stringify(array2))
{
    // your code here
}
gmsi
quelle
1
Scheint gut für den Vergleich verschachtelter Arrays und wenn die Reihenfolge wichtig ist.
Pierre de LESPINAY
3

Ich fand diese Diskussion, weil ich einen Weg brauchte, um Arrays und Objekte gründlich zu vergleichen. Anhand der Beispiele hier habe ich Folgendes gefunden (der Klarheit halber in drei Methoden unterteilt):

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

Testen

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
Vinny Alves
quelle
3

In meinem Fall enthalten verglichene Arrays nur Zahlen und Zeichenfolgen . Diese Lösung hat bei mir funktioniert:

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

Lass es uns testen!

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
yesnik
quelle
1

Ich glaube nicht, dass es eine gute "jQuery" -Methode gibt, aber wenn Sie Effizienz benötigen, ordnen Sie eines der Arrays einem bestimmten Schlüssel (einem der eindeutigen Objektfelder) zu und führen Sie dann einen Vergleich durch, indem Sie das andere Array durchlaufen und Vergleich mit der Karte oder dem assoziativen Array, das Sie gerade erstellt haben.

Wenn Effizienz kein Problem ist, vergleichen Sie einfach jedes Objekt in A mit jedem Objekt in B. Solange | A | und | B | klein sind, solltest du okay sein.

Stefan Kendall
quelle
@Stefan, danke für die schnelle Antwort. Können Sie Beispielcode für Ihre Mapping-Idee veröffentlichen? Vielen Dank.
MegaMatt
1

Wenn Sie nur den Inhalt von Arrays vergleichen möchten, gibt es eine nützliche jQuery-Funktion $ .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
Vilius Paulauskas
quelle
Gute Lösung, aber ich bin nicht sicher, ob dies dafür verantwortlich ist, dass die Arrays dieselben Elemente haben, aber in einer anderen Reihenfolge.
MegaMatt
Sie können sich bewegen, wenn (! Equal) false zurückgibt. bis zum Ende von $ .each, um ein erneutes Auslösen der Funktion zu vermeiden. Und du kannst gleich zurückkehren; einen Vergleich zu vermeiden.
Matt
1

Ändern Sie das Array in Zeichenfolge und vergleichen Sie

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

Der nette Einzeiler von Sudhakar R als globale jQuery-Methode.

/**
 * 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;
  }
});
Fleischwolf
quelle
0

Ich fand dies auch, als ich nach Array-Vergleichen mit jQuery suchte. In meinem Fall hatte ich Strings, von denen ich wusste, dass sie Arrays sind:

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

Aber es war mir wichtig, ob es sich um ein vollständiges oder nur ein teilweises Spiel handelte, also habe ich Folgendes verwendet, basierend auf der Antwort von 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';
  }
}
Spund
quelle
0

Wenn Duplikate so wichtig sind, dass [1, 1, 2]sie nicht gleich, [2, 1]aber gleich sein sollten [1, 2, 1], finden Sie hier eine Referenzzähllösung:

  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()}

Hier ist die Geige zum Spielen .

Paul Whipp
quelle
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>

Parth Raval
quelle
-3

Versuche dies

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;
}
Ausnahme
quelle
Das ändert sowohl a als auch b und vergleicht nur das erste Element. wtf.
ScottJ
1
@ScottJ Mr.AH Die Frage ist, zwei Arrays zu vergleichen. Nach dem Sortieren, ob beide Arrays gleich sind a [0] == b [0]. wtf du bah.
Ausnahme
2
Ich fürchte, ich weiß nicht, was AH bedeutet, und Google war keine Hilfe. Aber wenn mein Kommentar so falsch war, warum wurde dieser Code am 21. Februar komplett neu geschrieben?
ScottJ
@ScottJ Höchstwahrscheinlich AH === wtf
Ausnahme