Comment vérifier si deux tableaux sont égaux avec JavaScript? [dupliquer]

cette question a déjà une réponse ici:

  • comment comparer des tableaux en JavaScript? 49 réponses
var a = [1, 2, 3];
var b = [3, 2, 1];
var c = new Array(1, 2, 3);

alert(a == b + "|" + b == c);

démo

Comment puis-je vérifier ces tableaux pour l'égalité et obtenir une méthode qui retourne true si elles sont l'égalité?

est-ce que jQuery offre une méthode pour cela?

180
demandé sur Martin Thoma 2010-06-25 10:24:22

16 réponses

C'est ce que vous devez faire. N'utilisez pas stringify ni < > .

function arraysEqual(a, b) {
  if (a === b) return true;
  if (a == null || b == null) return false;
  if (a.length != b.length) return false;

  // If you don't care about the order of the elements inside
  // the array, you should sort both arrays here.
  // Please note that calling sort on an array will modify that array.
  // you might want to clone your array first.

  for (var i = 0; i < a.length; ++i) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}
197
répondu enyo 2018-09-22 19:56:08

Option 1

option la plus facile, fonctionne dans presque tous les cas, sauf que null != = undefined mais ils sont tous les deux convertis en représentation JSON null et considérés comme égaux:

function arraysEqual(a1,a2) {
    /* WARNING: arrays must not contain {objects} or behavior may be undefined */
    return JSON.stringify(a1)==JSON.stringify(a2);
}

( Cela pourrait ne pas fonctionner si votre tableau contient des objets. si cela fonctionne toujours avec les objets dépend de si l'implémentation JSON trie les clés. Par exemple, le JSON de {1:2,3:4} peut ou ne peut pas être égal à {3:4,1:2} ; cela dépend de la mise en œuvre, et le spec ne fait aucune garantie quelle qu'elle soit. [Mise à jour 2017: en fait la spécification ES6 garantit maintenant que les clés d'objet seront itérées dans l'ordre de 1) propriétés entières, 2) Propriétés dans l'ordre où elles ont été définies, puis 3) propriétés de symboles dans l'ordre où elles ont été définies. Donc si le JSON.l'implémentation de stringify suit Ceci, des objets égaux (dans le sens === mais pas nécessairement dans le sens==) vont stringify à l'égalité des valeurs. Plus de recherche est nécessaire. Donc je suppose que vous pourriez faire un clone maléfique d'un objet avec des propriétés dans l'ordre inverse, mais je ne peux pas imaginer que cela arrive par accident...] au moins sur Chrome, le JSON.la fonction stringify a tendance à renvoyer les clés dans l'ordre où elles ont été définies (du moins que j'ai remarqué), mais ce comportement est très sujet à changement à tout moment et ne devrait pas être utilisé. si vous choisissez de ne pas utiliser d'objets dans vos listes, ceci devrait fonctionner correctement. Si vous avez des objets dans votre liste qui ont tous un identifiant unique, vous pouvez faire a1.map(function(x)}{return {id:x.uniqueId}}) . Si vous avez des objets arbitraires dans votre liste, vous pouvez lire l'option #2.)

Cela fonctionne pour les tableaux imbriqués.

il est, cependant, un peu inefficace en raison de la surabondance de créer ces cordes et de collecte des ordures.


Option 2

option" plus "propre", que vous pouvez remplacer pour traiter des cas spéciaux (comme les objets réguliers et les objets null/undefined et personnalisés, si vous le souhaitez):

// generally useful functions
function type(x) { // does not work in general, but works on JSONable objects we care about... modify as you see fit
    // e.g.  type(/asdf/g) --> "[object RegExp]"
    return Object.prototype.toString.call(x);
}
function zip(arrays) {
    // e.g. zip([[1,2,3],[4,5,6]]) --> [[1,4],[2,5],[3,6]]
    return arrays[0].map(function(_,i){
        return arrays.map(function(array){return array[i]})
    });
}

// helper functions
function allCompareEqual(array) {
    // e.g.  allCompareEqual([2,2,2,2]) --> true
    // does not work with nested arrays or objects
    return array.every(function(x){return x==array[0]});
}

function isArray(x){ return type(x)==type([]) }
function getLength(x){ return x.length }
function allTrue(array){ return array.reduce(function(a,b){return a&&b},true) }
    // e.g. allTrue([true,true,true,true]) --> true
    // or just array.every(function(x){return x});

function allDeepEqual(things) {
    // works with nested arrays
    if( things.every(isArray) )
        return allCompareEqual(things.map(getLength))     // all arrays of same length
               && allTrue(zip(things).map(allDeepEqual)); // elements recursively equal

    //else if( this.every(isObject) )
    //  return {all have exactly same keys, and for 
    //          each key k, allDeepEqual([o1[k],o2[k],...])}
    //  e.g. ... && allTrue(objectZip(objects).map(allDeepEqual)) 

    //else if( ... )
    //  extend some more

    else
        return allCompareEqual(things);
}

Démo:

allDeepEqual([ [], [], [] ])
true
allDeepEqual([ [1], [1], [1] ])
true
allDeepEqual([ [1,2], [1,2] ])
true
allDeepEqual([ [[1,2],[3]], [[1,2],[3]] ])
true

allDeepEqual([ [1,2,3], [1,2,3,4] ])
false
allDeepEqual([ [[1,2],[3]], [[1,2],[],3] ])
false
allDeepEqual([ [[1,2],[3]], [[1],[2,3]] ])
false
allDeepEqual([ [[1,2],3], [1,[2,3]] ])
false

pour utiliser ceci comme une fonction régulière, faire:

function allDeepEqual2() {
    return allDeepEqual([].slice.call(arguments));
}

Démo:

allDeepEqual2([[1,2],3], [[1,2],3])
true

Options 3

edit : nous sommes en 2016 et ma réponse précédente, trop compliquée, me dérangeait. Cette implémentation recursive et impérative "recursive programming 101" maintient le code très simple, et échoue en outre le plus tôt possible (ce qui nous donne de l'efficacité). Il ne génère pas non plus d'infrastructures de données éphémères superflues (non pas qu'il y ait quelque chose de mal à la programmation fonctionnelle en général, mais juste la garder propre ici).

si nous voulions appliquer cela à des tableaux de tableaux non vides, nous pourrions faire des séries de barres.réduire (arraysEqual).

C'est sa propre fonction, par opposition à l'utilisation de l'Objet.defineProperties à joindre à la Matrice.prototype, puisque cela échouerait avec une erreur clé si nous réussissions dans une valeur non définie (qui est cependant une bonne décision de conception si vous voulez le faire).

Cela ne répond OPs original question.

function arraysEqual(a,b) {
    /*
        Array-aware equality checker:
        Returns whether arguments a and b are == to each other;
        however if they are equal-lengthed arrays, returns whether their 
        elements are pairwise == to each other recursively under this
        definition.
    */
    if (a instanceof Array && b instanceof Array) {
        if (a.length!=b.length)  // assert same length
            return false;
        for(var i=0; i<a.length; i++)  // assert each element equal
            if (!arraysEqual(a[i],b[i]))
                return false;
        return true;
    } else {
        return a==b;  // if not both arrays, should be the same
    }
}

exemples:

arraysEqual([[1,2],3], [[1,2],3])
true
arraysEqual([1,2,3], [1,2,3,4])
false
arraysEqual([[1,2],[3]], [[1,2],[],3])
false
arraysEqual([[1,2],[3]], [[1],[2,3]])
false
arraysEqual([[1,2],3], undefined)
false
arraysEqual(undefined, undefined)
true
arraysEqual(1, 2)
false
arraysEqual(null, null)
true
arraysEqual(1, 1)
true
arraysEqual([], 1)
false
arraysEqual([], undefined)
false
arraysEqual([], [])
true

si vous voulez appliquer ceci à des structures de données de type JSON avec des objets js, vous pouvez le faire. Heureusement, nous sommes assurés que toutes les clés d'objets sont uniques, alors itérez au-dessus des propriétés des objets et classez-les par clé, puis affirmez que les deux clés triées-tableau est égal et la valeur-tableau sont égaux, et juste recurse. Nous pouvons étendre ce d'inclure des Cartes (où les touches sont aussi unique.) (Cependant si nous étendons ceci aux ensembles, nous courons dans le problème d'isomorphisme de l'arbre http://logic.pdmi.ras.ru / ~smal/files / smal_jass08_slides.pdf - heureusement, ce n'est pas aussi difficile que l'isomorphisme général du Graphe; il y a en fait un algorithme O(#vertices) pour le résoudre, mais il peut devenir très compliqué de le faire efficacement. Le cas pathologique est si vous avez un ensemble composé de beaucoup d'objets apparemment-indistinguible, mais après une inspection plus poussée certains de ces objets peuvent diffèrent comme vous plonger plus profondément en eux. Vous pouvez également contourner cela en utilisant le hachage pour rejeter presque tous les cas.)


Option 4: (suite de l'édition 2016)

cela devrait fonctionner avec la plupart des objets:

function deepEquals(a,b) {
    if (a instanceof Array && b instanceof Array)
        return arraysEqual(a,b);
    if (Object.getPrototypeOf(a)===Object.prototype && Object.getPrototypeOf(b)===Object.prototype)
        return objectsEqual(a,b);
    if (a instanceof Map && b instanceof Map)
        return mapsEqual(a,b);        
    if (a instanceof Set && b instanceof Set)
        throw "Error: set equality by hashing not implemented."
    if ((a instanceof ArrayBuffer || ArrayBuffer.isView(a)) && (b instanceof ArrayBuffer || ArrayBuffer.isView(b)))
        return typedArraysEqual(a,b);
    return a==b;  // see note[1] -- IMPORTANT
}

function arraysEqual(a,b) {
    if (a.length!=b.length)
        return false;
    for(var i=0; i<a.length; i++)
        if (!deepEquals(a[i],b[i]))
            return false;
    return true;
}
function objectsEqual(a,b) {
    var aKeys = Object.getOwnPropertyNames(a);
    var bKeys = Object.getOwnPropertyNames(b);
    if (aKeys.length!=bKeys.length)
        return false;
    aKeys.sort();
    bKeys.sort();
    for(var i=0; i<aKeys.length; i++)
        if (aKeys[i]!=bKeys[i]) // keys must be strings
            return false;
    return deepEquals(aKeys.map(k=>a[k]), aKeys.map(k=>b[k]));
}
function mapsEqual(a,b) {
    if (a.size!=b.size)
        return false;
    var aPairs = Array.from(a);
    var bPairs = Array.from(b);
    aPairs.sort((x,y) => x[0]<y[0]);
    bPairs.sort((x,y) => x[0]<y[0]);
    for(var i=0; i<a.length; i++)
        if (!deepEquals(aPairs[i][0],bPairs[i][0]) || !deepEquals(aPairs[i][1],bPairs[i][1]))
            return false;
    return true;
}
function typedArraysEqual(a,b) {
    a = new Uint8Array(a);
    b = new Uint8Array(b);
    if (a.length != b.length)
        return false;
    for(var i=0; i<a.length; i++)
        if (a[i]!=b[i])
            return false;
    return true;
}

Démo (pas testé):

var nineTen = new Float32Array(2);
nineTen[0]=9; nineTen[1]=10;
deepEquals(
    [[1,[2,3]], 4, {a:5,b:6}, new Map([['c',7],['d',8]]), nineTen],
    [[1,[2,3]], 4, {b:6,a:5}, new Map([['d',8],['c',7]]), nineTen]
)

(note: les Cartes sont es6 dictionnaires. Je ne peux pas dire si ils ont O(1) O(log(N)) performances de recherche, mais dans tous les cas, ils sont "ordonnés" en ce sens qu'ils suivent l'ordre dans lequel des paires de valeurs clés ont été insérées. Toutefois, la sémantique selon laquelle deux cartes doivent être égales si des éléments y sont insérés dans un ordre différent est ambiguë. Je donne ci-dessous un exemple d'implémentation d'un deepEquals qui considère deux cartes égales même si des éléments y ont été insérés dans un ordre différent.)

(note [1]: IMPORTANT: NOTION D'égalité: vous peut-être voulez-vous outrepasser la ligne notée avec une notion coutumière d'Égalité, que vous devrez également changer dans les autres fonctions où qu'elle apparaisse. Par exemple, voulez-vous ou non NaN==NaN? Par défaut, ce n'est pas le cas. Il y a des choses encore plus bizarres comme 0=='0'. Considérez-vous que deux objets sont les mêmes si et seulement s'ils sont le même objet en mémoire? Voir https://stackoverflow.com/a/5447170/711085 . Vous devez documenter la notion d'égalité que vous utilisez. )

vous devriez être en mesure d'étendre le ci-dessus à WeakMaps, WeakSets. Je ne sais pas s'il est logique d'étendre à DataViews. Devrait également pouvoir s'étendre à RegExps probablement, etc.

en l'étendant, vous réalisez que vous faites beaucoup de comparaisons inutiles. C'est là que la fonction type que j'ai définie plus tôt (solution #2) peut être utile; alors vous pouvez envoyer instantanément. Si cela vaut la peine de la surcharge de (éventuellement? pas bien sûr, comment cela fonctionne sous le capot) chaîne représentant le type est à vous. Vous pouvez alors réécrire le dispatcher, i.e. la fonction deepEquals , pour être quelque chose comme:

var dispatchTypeEquals = {
    number: function(a,b) {...a==b...},
    array: function(a,b) {...deepEquals(x,y)...},
    ...
}
function deepEquals(a,b) {
    var typeA = extractType(a);
    var typeB = extractType(a);
    return typeA==typeB && dispatchTypeEquals[typeA](a,b);
}
105
répondu ninjagecko 2018-08-30 23:54:37

jQuery n'a pas de méthode pour comparer des tableaux. Toutefois ,la bibliothèque Underscore (ou la bibliothèque lodash comparable) a une telle méthode: isEqual , et il peut traiter une variété d'autres cas (comme les littérales d'objet) ainsi. Pour s'en tenir à l'exemple fourni:

var a=[1,2,3];
var b=[3,2,1];
var c=new Array(1,2,3);

alert(_.isEqual(a, b) + "|" + _.isEqual(b, c));

par ailleurs: Underscore a beaucoup d'autres méthodes que jQuery est absent ainsi, il est un excellent complément à jQuery.

EDIT: , Comme cela a été souligné dans les commentaires, ci-dessus maintenant ne fonctionne que si les deux tableaux ont leurs éléments dans le même ordre, c'est à dire.:

_.isEqual([1,2,3], [1,2,3]); // true
_.isEqual([1,2,3], [3,2,1]); // false

heureusement Javascript a une méthode intégrée pour résoudre ce problème exact, sort :

_.isEqual([1,2,3].sort(), [3,2,1].sort()); // true
62
répondu machineghost 2016-12-05 19:24:04

pour les valeurs primitives comme les nombres et les chaînes, c'est une solution facile:

a = [1,2,3]

b = [3,2,1]

a.sort().toString() == b.sort().toString() 

l'appel à sort() garantira que l'ordre des éléments n'a pas d'importance. L'appel toString() créera une chaîne avec les valeurs séparées par une virgule pour que les deux chaînes puissent être testées pour l'égalité.

25
répondu soheildb 2017-07-15 08:09:08

avec JavaScript version 1.6 c'est aussi simple que cela:

Array.prototype.equals = function( array ) {
  return this.length == array.length && 
         this.every( function(this_i,i) { return this_i == array[i] } )  
  }

par exemple, [].equals([]) donne true , tandis que [1,2,3].equals( [1,3,2] ) donne false .

19
répondu rplantiko 2013-10-21 12:11:25

basé sur Tim James réponse et le commentaire de Fox32, ce qui suit devrait vérifier les nulls, avec la supposition que deux nulls ne sont pas égaux.

function arrays_equal(a,b) { return !!a && !!b && !(a<b || b<a); }

> arrays_equal([1,2,3], [1,3,4])
false
> arrays_equal([1,2,3], [1,2,3])
true
> arrays_equal([1,3,4], [1,2,3])
false
> arrays_equal(null, [1,2,3])
false
> arrays_equal(null, null)
false
6
répondu stantont 2017-05-23 11:55:01

même si cela peut sembler très simple, parfois c'est vraiment utile. Si tout ce que vous avez besoin est de voir si deux tableaux ont les mêmes éléments et ils sont dans le même ordre, essayez ceci:

[1, 2, 3].toString() == [1, 2, 3].toString()
true
[1, 2, 3,].toString() == [1, 2, 3].toString()
true
[1,2,3].toString() == [1, 2, 3].toString()
true

cependant, cela ne fonctionne pas pour les cas avancés de mode tels que:

[[1,2],[3]].toString() == [[1],[2,3]].toString()
true

cela dépend de ce dont vous avez besoin.

5
répondu Clawsy 2012-06-22 06:41:22

jQuery a une telle méthode profonde comparaison récursive .

Une maison à usage général égalité stricte check pourrait ressembler à ce qui suit:

function deepEquals(obj1, obj2, parents1, parents2) {
    "use strict";
    var i;
    // compare null and undefined
    if (obj1 === undefined || obj2 === undefined || 
        obj1 === null || obj2 === null) {
        return obj1 === obj2;
    }

    // compare primitives
    if (typeof (obj1) !== 'object' || typeof (obj2) !== 'object') {
        return obj1.valueOf() === obj2.valueOf();
    }

    // if objects are of different types or lengths they can't be equal
    if (obj1.constructor !== obj2.constructor || (obj1.length !== undefined && obj1.length !== obj2.length)) {
        return false;
    }

    // iterate the objects
    for (i in obj1) {
        // build the parents list for object on the left (obj1)
        if (parents1 === undefined) parents1 = [];
        if (obj1.constructor === Object) parents1.push(obj1);
        // build the parents list for object on the right (obj2)
        if (parents2 === undefined) parents2 = [];
        if (obj2.constructor === Object) parents2.push(obj2);
        // walk through object properties
        if (obj1.propertyIsEnumerable(i)) {
            if (obj2.propertyIsEnumerable(i)) {
                // if object at i was met while going down here
                // it's a self reference
                if ((obj1[i].constructor === Object && parents1.indexOf(obj1[i]) >= 0) || (obj2[i].constructor === Object && parents2.indexOf(obj2[i]) >= 0)) {
                    if (obj1[i] !== obj2[i]) {
                        return false;
                    }
                    continue;
                }
                // it's not a self reference so we are here
                if (!deepEquals(obj1[i], obj2[i], parents1, parents2)) {
                    return false;
                }
            } else {
                // obj2[i] does not exist
                return false;
            }
        }
    }
    return true;
};

Essais:

// message is displayed on failure
// clean console === all tests passed
function assertTrue(cond, msg) {
    if (!cond) {
        console.log(msg);
    }
}

var a = 'sdf',
    b = 'sdf';
assertTrue(deepEquals(b, a), 'Strings are equal.');
b = 'dfs';
assertTrue(!deepEquals(b, a), 'Strings are not equal.');
a = 9;
b = 9;
assertTrue(deepEquals(b, a), 'Numbers are equal.');
b = 3;
assertTrue(!deepEquals(b, a), 'Numbers are not equal.');
a = false;
b = false;
assertTrue(deepEquals(b, a), 'Booleans are equal.');
b = true;
assertTrue(!deepEquals(b, a), 'Booleans are not equal.');
a = null;
assertTrue(!deepEquals(b, a), 'Boolean is not equal to null.');
a = function () {
    return true;
};
assertTrue(deepEquals(
[
    [1, 1, 1],
    [2, 'asdf', [1, a]],
    [3, {
        'a': 1.0
    },
    true]
], 
[
    [1, 1, 1],
    [2, 'asdf', [1, a]],
    [3, {
        'a': 1.0
    },
    true]
]), 'Arrays are equal.');
assertTrue(!deepEquals(
[
    [1, 1, 1],
    [2, 'asdf', [1, a]],
    [3, {
        'a': 1.0
    },
    true]
],
[
    [1, 1, 1],
    [2, 'asdf', [1, a]],
    [3, {
        'a': '1'
    },
    true]
]), 'Arrays are not equal.');
a = {
    prop: 'val'
};
a.self = a;
b = {
    prop: 'val'
};
b.self = a;
assertTrue(deepEquals(b, a), 'Immediate self referencing objects are equal.');
a.prop = 'shmal';
assertTrue(!deepEquals(b, a), 'Immediate self referencing objects are not equal.');
a = {
    prop: 'val',
    inside: {}
};
a.inside.self = a;
b = {
    prop: 'val',
    inside: {}
};
b.inside.self = a;
assertTrue(deepEquals(b, a), 'Deep self referencing objects are equal.');
b.inside.self = b;
assertTrue(!deepEquals(b, a), 'Deep self referencing objects are not equeal. Not the same instance.');
b.inside.self = {foo: 'bar'};
assertTrue(!deepEquals(b, a), 'Deep self referencing objects are not equal. Completely different object.');
a = {};
b = {};
a.self = a;
b.self = {};
assertTrue(!deepEquals(b, a), 'Empty object and self reference of an empty object.');
5
répondu uKolka 2013-08-18 22:19:35

Vérifier chaque valeur par une boucle une fois que vous avez vérifié la taille du tableau.

function equalArray(a, b) {
    if (a.length === b.length) {
        for (var i = 0; i < a.length; i++) {
            if (a[i] !== b[i]) {
                return false;
            }
        }
        return true;
    } else {
        return false;
    }
}
4
répondu DOCTYPE HTML 2017-07-15 07:54:56

utilisant map() et reduce() :

function arraysEqual (a1, a2) {
    return a1 === a2 || (
        a1 !== null && a2 !== null &&
        a1.length === a2.length &&
        a1
            .map(function (val, idx) { return val === a2[idx]; })
            .reduce(function (prev, cur) { return prev && cur; }, true)
    );
}
2
répondu Chitharanjan Das 2015-09-23 10:27:10

Il n'y a pas de moyen facile de le faire. J'en avais aussi besoin, mais je voulais une fonction qui puisse prendre deux variables et tester l'égalité. Cela inclut les valeurs non-objet, les objets, les tableaux et n'importe quel niveau d'imbrication.

Dans votre question, vous mentionnez vouloir ignorer l'ordre des valeurs dans un tableau. Ma solution ne le fait pas en soi, mais vous pouvez y parvenir en triant les tableaux avant de comparer pour l'égalité

je voulais aussi le l'option de la coulée de non-objets à cordes de sorte que [1,2]===["1",2]

puisque mon projet utilise des sous-titres, j'ai décidé d'en faire un mixin plutôt qu'une fonction autonome.

vous pouvez le tester sur http://jsfiddle.net/nemesarial/T44W4 /

Voici mon mxin:

_.mixin({
  /**
  Tests for the equality of two variables
    valA: first variable
    valB: second variable
    stringifyStatics: cast non-objects to string so that "1"===1
  **/
  equal:function(valA,valB,stringifyStatics){
    stringifyStatics=!!stringifyStatics;

    //check for same type
    if(typeof(valA)!==typeof(valB)){
      if((_.isObject(valA) || _.isObject(valB))){
        return false;
      }
    }

    //test non-objects for equality
    if(!_.isObject(valA)){
      if(stringifyStatics){
        var valAs=''+valA;
        var valBs=''+valB;
        ret=(''+valA)===(''+valB);
      }else{
        ret=valA===valB;
      }
      return ret;
    }

    //test for length
    if(_.size(valA)!=_.size(valB)){
      return false;
    }

    //test for arrays first
    var isArr=_.isArray(valA);

    //test whether both are array or both object
    if(isArr!==_.isArray(valB)){
      return false;
    }

    var ret=true;
    if(isArr){
      //do test for arrays
      _.each(valA,function(val,idx,lst){
        if(!ret){return;}
        ret=ret && _.equal(val,valB[idx],stringifyStatics);
      });
    }else{
      //do test for objects
      _.each(valA,function(val,idx,lst){
        if(!ret){return;}

        //test for object member exists
        if(!_.has(valB,idx)){
          ret=false;
          return;
        }

        // test for member equality
        ret=ret && _.equal(val,valB[idx],stringifyStatics);
      });

    }
    return ret;
  }
});

Voici comment vous l'utilisez:

_.equal([1,2,3],[1,2,"3"],true)

pour démontrer la nidification, vous pouvez faire ceci:

_.equal(
    ['a',{b:'b',c:[{'someId':1},2]},[1,2,3]],
    ['a',{b:'b',c:[{'someId':"1"},2]},["1",'2',3]]
,true);
1
répondu Nemesarial 2013-11-06 08:45:20

si vous souhaitez cocher tableaux d'objets pour l'égalité et l'ordre n'a pas d'importance, i.e.

areEqual([{id: "0"}, {id: "1"}], [{id: "1"}, {id: "0"}]) // true

vous devez d'abord trier les tableaux. lodash dispose de tous les outils dont vous avez besoin, en combinant sortBy et isEqual :

// arr1 & arr2: Arrays of objects 
// sortProperty: the property of the object with which you want to sort
// Note: ensure every object in both arrays has your chosen sortProperty
// For example, arr1 = [{id: "v-test_id0"}, {id: "v-test_id1"}]
// and          arr2 = [{id: "v-test_id1"}, {id: "v-test_id0"}]
// sortProperty should be 'id'

function areEqual (arr1, arr2, sortProperty) {
  return _.areEqual(_.sortBy(arr1, sortProperty), _.sortBy(arr2, sortProperty))
}

EDIT: puisque sortBy retourne un nouveau tableau, il n'est pas nécessaire de cloner vos tableaux avant de les trier. Le les matrices originales ne seront pas modifiées.

Notez que pour lodash isEqual , l'ordre a de l'importance . L'exemple ci-dessus retournera false si sortBy n'est pas appliqué à chaque tableau en premier.

1
répondu willyhusted 2016-02-03 17:37:03

Si vous utilisez lodash et ne voulez pas modifier array, vous pouvez utiliser la fonction _.xor () . Il compare les deux tableaux comme des ensembles et retourne l'ensemble qui contient leur différence. Si la longueur de cette différence est zéro, les deux tableaux sont essentiellement égaux:

var a = [1, 2, 3];
var b = [3, 2, 1];
var c = new Array(1, 2, 3);
_.xor(a, b).length === 0
true
_.xor(b, c).length === 0
true
1
répondu Chase Sandmann 2016-06-23 23:02:30

il manipule toutes les choses possibles et même de référence lui-même dans la structure de l'objet. Vous pouvez voir l'exemple à la fin du code.

var deepCompare = (function() {
    function internalDeepCompare (obj1, obj2, objects) {
        var i, objPair;

        if (obj1 === obj2) {
            return true;
        }

        i = objects.length;
        while (i--) {
            objPair = objects[i];
            if (  (objPair.obj1 === obj1 && objPair.obj2 === obj2) ||
                  (objPair.obj1 === obj2 && objPair.obj2 === obj1)  ) {                          
                return true;
            }                    
        }
        objects.push({obj1: obj1, obj2: obj2});

        if (obj1 instanceof Array) {
            if (!(obj2 instanceof Array)) {
                return false;
            }

            i = obj1.length;

            if (i !== obj2.length) {
               return false; 
            }

            while (i--) {
                if (!internalDeepCompare(obj1[i], obj2[i], objects)) {
                    return false;
                }
            }
        }
        else {
            switch (typeof obj1) {
                case "object":                
                    // deal with null
                    if (!(obj2 && obj1.constructor === obj2.constructor)) {
                        return false;
                    }

                    if (obj1 instanceof RegExp) {
                        if (!(obj2 instanceof RegExp && obj1.source === obj2.source)) {
                            return false;
                        }
                    }                 
                    else if (obj1 instanceof Date) {
                        if (!(obj2 instanceof Date && obj1.getTime() === obj2.getTime())) {
                            return false;
                        }
                    } 
                    else {    
                        for (i in obj1) {
                            if (obj1.hasOwnProperty(i)) {       
                                if (!(obj2.hasOwnProperty(i) && internalDeepCompare(obj1[i], obj2[i], objects))) {
                                    return false;
                                }
                            }
                        }         
                    }
                    break;
                case "function": 
                    if (!(typeof obj2 === "function" && obj1+"" === obj2+"")) {
                        return false;
                    }
                    break;
                default:                 //deal with NaN 
                    if (obj1 !== obj2 && obj1 === obj1 && obj2 === obj2) {
                        return false;            
                    }
            }
        }

        return true;
    }

    return function (obj1, obj2) {
        return internalDeepCompare(obj1, obj2, []);    
    };
}());

/*    
var a = [a, undefined, new Date(10), /.+/, {a:2}, function(){}, Infinity, -Infinity, NaN, 0, -0, 1, [4,5], "1", "-1", "a", null],
    b = [b, undefined, new Date(10), /.+/, {a:2}, function(){}, Infinity, -Infinity, NaN, 0, -0, 1, [4,5], "1", "-1", "a", null];
deepCompare(a, b);
*/
0
répondu Marc Devol 2015-01-27 23:41:17

cette méthode craint, mais je l'ai laissée ici pour référence afin que d'autres évitent ce chemin:


en utilisant l'Option 1 de @ninjagecko a fonctionné le mieux pour moi:

Array.prototype.equals = function(array) {
    return array instanceof Array && JSON.stringify(this) === JSON.stringify(array) ;
}

a = [1, [2, 3]]
a.equals([[1, 2], 3]) // false
a.equals([1, [2, 3]]) // true

il traitera aussi le cas null et non défini, puisque nous ajoutons cela au prototype de array et vérifions que l'autre argument est aussi un array.

-1
répondu Aram Kocharyan 2013-05-08 13:21:42
var a= [1, 2, 3, '3'];
var b = [1, 2, 3];

var c = a.filter(function (i) { return ! ~b.indexOf(i); });

alert(c.length);
-1
répondu KOstyantin 2015-01-23 12:29:19