web-dev-qa-db-fra.com

Utilisation de jQuery pour comparer deux tableaux d'objets Javascript

J'ai deux tableaux d'objets JavaScript que j'aimerais comparer pour voir s'ils sont identiques. Les objets peuvent ne pas (et probablement pas) être dans le même ordre dans chaque tableau. Chaque tableau ne devrait 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 en trouver beaucoup en ligne.

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

Merci.

90
MegaMatt

Il y a un moyen facile ...

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

Si ce qui précède renvoie la valeur 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 de jquery <3.0.0 lorsque des objets JSON sont utilisés.

273
Sudhakar R

Je cherchais aussi ceci aujourd'hui et trouve: http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD

Je ne sais pas si c'est une bonne solution mais ils mentionnent certaines considérations de performance prises en compte.

J'aime l'idée d'une méthode d'assistance jQuery . @ David Je préférerais que votre méthode de comparaison fonctionne de la manière suivante:

jQuery.compare(a, b)

Je n'ai pas de sens pour moi de faire:

$(a).compare(b)

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

Également en ce qui concerne 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 dans la boucle soit une "mise en cache". Le tri aura toujours lieu chaque fois que vous appelez compare (b). C'est juste la sémantique, mais ...
  • pour (var i = 0; t [i]; i ++) { ... cette boucle se termine plus tôt si votre tableau t contient une valeur fausse quelque part, alors $ ( [1, 2, 3, 4]). Compare ([1, false, 2, 3]) renvoie vrai!
  • Plus important encore, la méthode array sort () trie le tableau à la place, de sorte que var b = t.sort () ... ne crée pas une copie triée du tableau d'origine, il trie le tableau original et lui affecte également un référence dans 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 le faire de manière jQuery était de nul autre que John Resig ici sur SO! Quel est le moyen le plus efficace de cloner en profondeur un objet en JavaScript?(voir les commentaires sur sa réponse pour la version de tableau de la recette de clonage d'objets))

Dans ce cas, je pense que le code pour ce 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]
34
Anentropic

Mon approche était assez différente: j'ai effacé les deux collections à l'aide de JSON.stringify et utilisé une comparaison de chaîne normale 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!

14
Kwex

Convertir les deux tableaux en chaîne et comparer

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

J'ai trouvé cette discussion parce qu'il me fallait un moyen de comparer en profondeur des tableaux et des objets. En utilisant les exemples ci-dessous, je propose les éléments suivants (répartis 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
3
Vinny Alves

Dans mon cas, les tableaux comparés ne contiennent que nombres et 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
2
yesnik

Je ne pense pas qu'il existe un bon moyen "jQuery" de le faire, mais si vous avez besoin d'efficacité, mappez l'un des tableaux à l'aide d'une certaine clé (l'un des champs d'objet uniques), puis effectuez la comparaison en boucle à travers 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.

1
Stefan Kendall

Le Nice 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;
  }
});
1
Fleshgrinder

Eh bien, si vous voulez 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
1
Vilius Paulauskas

Changer le tableau en chaîne et comparer

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

J'ai également trouvé cela lorsque je cherchais à 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 suis demandé si c'était un match complet ou seulement un match partiel. J'ai donc 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';
  }
}
0
Bung

Si les doublons importent pour que [1, 1, 2] ne soit pas égal à [2, 1] mais égal à [1, 2, 1], voici une solution de comptage des références

  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 à jouer avec .

0
Paul Whipp

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>

0
Parth Raval