Utilisation de jQuery pour comparer deux tableaux d'objets Javascript

93

J'ai deux tableaux d'objets JavaScript que j'aimerais comparer pour voir s'ils sont identiques. Les objets peuvent ne pas (et ne seront probablement pas) dans le même ordre dans chaque tableau. Chaque tableau ne doit pas avoir plus de 10 objets. Je pensais que jQuery pourrait avoir une solution élégante à ce problème, mais je n'ai pas pu trouver grand-chose en ligne.

Je sais qu'une $.each(array, function(){})solution imbriquée brute pourrait fonctionner, mais y a-t-il une fonction intégrée dont je ne suis pas au courant?

Merci.

MegaMatt
la source

Réponses:

277

Il existe un moyen simple ...

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

Si ce qui précède renvoie true, les deux tableaux sont identiques même si les éléments sont dans un ordre différent.

REMARQUE: cela ne fonctionne que pour les versions jquery <3.0.0 lors de l'utilisation d'objets JSON

suDocker
la source
12
+1, mais il est égal à vrai lorsque vous comparez un tableau avec un objet qui contient les mêmes propriétés, par exemple[0,1] == {0:0,1:1,length=2}
David Hellsing
4
pourquoi $(arr1).not(arr2).length == 0ne suffit pas?
Alexxus
10
@Alexxus, vous avez besoin des deux comparaisons car notc'est une fonction de filtre, pas une fonction d'égalité. Essayez-le avec [1,2]et [1]. Dans un ordre, vous obtiendrez [], et dans un autre, vous obtiendrez [2].
Noyo
3
Notez que si vous avez des doublons dans un tableau, cela retournera vrai. Donc quelque chose comme: `[1,1,2,2,3,3] == [1,2,3]` est vrai.
Philll_t
3
jQuery notne fonctionne plus avec les objets génériques à partir de 3.0.0-rc1. Voir github.com/jquery/jquery/issues/3147
Marc-André Lafortune
35

Je cherchais également ceci aujourd'hui et j'ai trouvé: http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD

Je ne sais pas si c'est une bonne solution, bien qu'ils mentionnent certaines considérations de performances prises en compte.

J'aime l'idée d'une méthode d'aide jQuery. @David Je préfère voir votre méthode de comparaison fonctionner comme:

jQuery.compare(a, b)

Je n'ai pas de sens à faire:

$(a).compare(b)

où a et b sont des tableaux. Normalement, lorsque vous $ (quelque chose), vous passez une chaîne de sélection pour travailler avec des éléments DOM.

En ce qui concerne également le tri et la mise en cache des tableaux triés:

  • Je ne pense pas que le tri une fois au début de la méthode au lieu de chaque fois à travers la boucle est une «mise en cache». Le tri se produira toujours à chaque fois que vous appelez compare (b). C'est juste de la sémantique, mais ...
  • for (var i = 0; t [i]; i ++) { ... cette boucle se termine tôt si votre tableau t contient une fausse valeur quelque part, donc $ ([1, 2, 3, 4]). compare ( [1, false, 2, 3]) renvoie vrai !
  • Plus important encore, la méthode array sort () trie le tableau sur place , donc faire var b = t.sort () ... ne crée pas une copie triée du tableau d'origine, elle trie le tableau d' origine et attribue également une référence à il en b . Je ne pense pas que la méthode de comparaison devrait avoir des effets secondaires.

Il semble que ce que nous devons faire est de copier les tableaux avant de travailler dessus. La meilleure réponse que j'ai pu trouver pour savoir comment faire cela d'une manière jQuery était par nul autre que John Resig ici sur SO! Quelle est la manière la plus efficace de cloner en profondeur un objet en JavaScript? (voir les commentaires sur sa réponse pour la version tableau de la recette de clonage d'objet)

Dans ce cas, je pense que le code pour cela serait:

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]
Anentropique
la source
2
en fait, je nommerais probablement cette méthode 'arrayCompare' plutôt que 'compare' puisque c'est la seule chose sur laquelle elle est conçue pour fonctionner ...
Anentropic
Spot sur en effet. Merci beaucoup.
dimitarvp
14

Mon approche était assez différente - j'ai aplati les deux collections en utilisant JSON.stringify et utilisé une chaîne normale de comparaison pour vérifier l'égalité.

C'est à dire

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: Veuillez noter que sa méthode suppose que les deux Collections sont triées de la même manière, sinon, cela vous donnerait un faux résultat!

Kwex
la source
1
J'avais besoin d'une méthode simple pour comparer les tableaux dans mes tests unitaires, assurant le même ordre pour les deux tableaux. C'est très gentil, merci.
aymericbeaumet
Merci d'avoir sauvé ma journée
Sourabh Kumar Sharma
12

Convertir les deux tableaux en chaîne et comparer

if (JSON.stringify(array1) == JSON.stringify(array2))
{
    // your code here
}
gmsi
la source
1
Semble bon pour comparer des tableaux imbriqués et quand l'ordre est important.
Pierre de LESPINAY
3

J'ai trouvé cette discussion parce que j'avais besoin d'un moyen de comparer en profondeur les tableaux et les objets. En utilisant les exemples ici, j'ai trouvé ce qui suit (divisé en 3 méthodes pour plus de clarté):

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

Essai

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
la source
3

Dans mon cas, les tableaux comparés ne contiennent que des nombres et des chaînes . Cette solution a fonctionné pour moi:

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

Testons-le!

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
la source
1

Je ne pense pas qu'il y ait un bon moyen "jQuery" de faire cela, mais si vous avez besoin d'efficacité, mappez l'un des tableaux par une certaine clé (l'un des champs d'objet uniques), puis faites une comparaison en passant par l'autre tableau et en comparant avec la carte, ou le tableau associatif, que vous venez de construire.

Si l'efficacité n'est pas un problème, comparez simplement chaque objet de A à chaque objet de B. Tant que | A | et | B | sont petits, ça devrait aller.

Stefan Kendall
la source
@Stefan, merci pour la réponse rapide. Pouvez-vous publier un exemple de code pour votre idée de cartographie? Merci.
MegaMatt
1

Eh bien, si vous souhaitez comparer uniquement le contenu des tableaux, il existe une fonction jQuery utile $ .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
la source
Bonne solution, mais je ne suis pas sûr que cela tienne compte des tableaux ayant les mêmes éléments, mais dans un ordre différent.
MegaMatt
Vous pouvez vous déplacer si (! Égal) retourne false; jusqu'au bas de $ .each pour éviter de déclencher à nouveau la fonction. Et vous pouvez revenir égal; pour éviter une comparaison.
Matt
1

Changer le tableau en chaîne et comparer

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

Le joli one liner de Sudhakar R comme méthode 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;
  }
});
Fleshgrinder
la source
0

J'ai également trouvé cela en cherchant à faire des comparaisons de tableaux avec jQuery. Dans mon cas, j'avais des chaînes que je savais être des tableaux:

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

Mais je me souciais si c'était une correspondance complète ou seulement une correspondance partielle, alors j'ai utilisé quelque chose comme ce qui suit, basé sur la réponse de 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';
  }
}
Bonde
la source
0

Si les doublons ont une importance telle qu'ils [1, 1, 2]ne devraient pas être égaux [2, 1]mais devraient être égaux [1, 2, 1], voici une solution de comptage de référence:

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

Voici le violon avec lequel jouer .

Paul Whipp
la source
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
la source
-3

Essaye ça

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;
}
Exception
la source
Cela modifie à la fois a et b et ne compare que le premier élément. wtf.
ScottJ
1
@ScottJ Mr.AH La question est de comparer deux tableaux .. Après avoir trié si les deux tableaux sont égaux a [0] == b [0]. wtf vous bah.
Exception
2
J'ai peur de ne pas savoir ce que signifie AH, et Google ne m'aide pas. Mais si mon commentaire était si décalé, pourquoi ce code a-t-il été complètement réécrit le 21 février?
ScottJ
@ScottJ Très probablement AH === wtf
Exception