web-dev-qa-db-fra.com

Comment comparer les tableaux en JavaScript?

Je voudrais comparer deux tableaux ... idéalement, efficacement. Rien d'extraordinaire, juste true si elles sont identiques, et false sinon. Sans surprise, l'opérateur de comparaison ne semble pas fonctionner.

var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2);    // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2));    // Returns true

JSON encodant chaque tableau, mais existe-t-il un moyen plus rapide ou "meilleur" de simplement comparer des tableaux sans avoir à parcourir chaque valeur?

762
Julian H. Lam

Pour comparer des tableaux, passez-les en boucle et comparez chaque valeur: 

Comparer des tableaux:

// Warn if overriding existing method
if(Array.prototype.equals)
    console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");
// attach the .equals method to Array's prototype to call it on any array
Array.prototype.equals = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time 
    if (this.length != array.length)
        return false;

    for (var i = 0, l=this.length; i < l; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].equals(array[i]))
                return false;       
        }           
        else if (this[i] != array[i]) { 
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;   
        }           
    }       
    return true;
}
// Hide method from for-in loops
Object.defineProperty(Array.prototype, "equals", {enumerable: false});

Usage:

[1, 2, [3, 4]].equals([1, 2, [3, 2]]) === false;
[1, "2,3"].equals([1, 2, 3]) === false;
[1, 2, [3, 4]].equals([1, 2, [3, 4]]) === true;
[1, 2, 1, 2].equals([1, 2, 1, 2]) === true;

Vous pouvez dire "Mais il est beaucoup plus rapide de comparer des chaînes - pas de boucles ..." eh bien, alors vous devriez noter qu'il y a des boucles. Première boucle récursive qui convertit Array en chaîne et seconde, qui compare deux chaînes. Donc, cette méthode est plus rapide que l’utilisation de string.

Je crois que de plus grandes quantités de données devraient toujours être stockées dans des tableaux, pas dans des objets. Cependant, si vous utilisez des objets, vous pouvez également les comparer partiellement.
Voici comment:

Comparer des objets:

J'ai dit plus haut que deux objets instances ne seront jamais égaux, même s'ils contiennent les mêmes données pour le moment:

({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666})  //false

Cela a une raison, car il peut y avoir, par exemple, variables privées dans des objets.

Cependant, si vous utilisez uniquement la structure d'objet pour contenir des données, la comparaison est toujours possible:

Object.prototype.equals = function(object2) {
    //For the first loop, we only check for types
    for (propName in this) {
        //Check for inherited methods and properties - like .equals itself
        //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
        //Return false if the return value is different
        if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
            return false;
        }
        //Check instance type
        else if (typeof this[propName] != typeof object2[propName]) {
            //Different types => not equal
            return false;
        }
    }
    //Now a deeper check using other objects property names
    for(propName in object2) {
        //We must check instances anyway, there may be a property that only exists in object2
            //I wonder, if remembering the checked values from the first loop would be faster or not 
        if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
            return false;
        }
        else if (typeof this[propName] != typeof object2[propName]) {
            return false;
        }
        //If the property is inherited, do not check any more (it must be equa if both objects inherit it)
        if(!this.hasOwnProperty(propName))
          continue;

        //Now the detail check and recursion

        //This returns the script back to the array comparing
        /**REQUIRES Array.equals**/
        if (this[propName] instanceof Array && object2[propName] instanceof Array) {
                   // recurse into the nested arrays
           if (!this[propName].equals(object2[propName]))
                        return false;
        }
        else if (this[propName] instanceof Object && object2[propName] instanceof Object) {
                   // recurse into another objects
                   //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
           if (!this[propName].equals(object2[propName]))
                        return false;
        }
        //Normal value comparison for strings and numbers
        else if(this[propName] != object2[propName]) {
           return false;
        }
    }
    //If everything passed, let's say YES
    return true;
}  

Cependant, rappelez-vous que celui-ci doit servir à comparer JSON comme des données, et non des instances de classe et autres choses. Si vous voulez comparer plusieurs objets compliqués, regardez cette réponse et sa fonction super longue .
Pour que cela fonctionne avec Array.equals, vous devez éditer un peu la fonction d'origine:

...
    // Check if we have nested arrays
    if (this[i] instanceof Array && array[i] instanceof Array) {
        // recurse into the nested arrays
        if (!this[i].equals(array[i]))
            return false;
    }
    /**REQUIRES OBJECT COMPARE**/
    else if (this[i] instanceof Object && array[i] instanceof Object) {
        // recurse into another objects
        //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
        if (!this[i].equals(array[i]))
            return false;
        }
    else if (this[i] != array[i]) {
...

J'ai créé un petit outil de test pour les deux fonctions .

Bonus: Tableaux imbriqués avec indexOf et contains

_ { Samy Bencherif a préparé } _ fonctions utiles pour le cas où vous recherchez un objet spécifique dans des tableaux imbriqués, disponibles ici: https://jsfiddle.net/SamyBencherif/8352y6yw/ _

780
Tomáš Zato

Bien que cela ne fonctionne que pour les tableaux scalaires (voir la note ci-dessous), il est court:

array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})

Rr, dans ECMAScript 6/CoffeeScript/TypeScript avec fonctions de flèche:

array1.length === array2.length && array1.every((value, index) => value === array2[index])

(Remarque: «scalaire» désigne ici les valeurs pouvant être comparées directement à l'aide de ===. Ainsi: nombres, chaînes, objets par référence, fonctions par référence. Voir la référence MDN pour plus d'informations sur les opérateurs de comparaison).

METTRE &AGRAVE; JOUR

D'après ce que j'ai lu dans les commentaires, trier le tableau et comparer peuvent donner un résultat précis:

array1.length === array2.length && array1.sort().every(function(value, index) { return value === array2.sort()[index]});

Par exemple:

array1 = [2,3,1,4];
array2 = [1,2,3,4];

Alors le code ci-dessus donnerait true

286
user2782196

J'aime utiliser la bibliothèque Underscore pour les projets de codage de corps/objets lourds ... dans Underscore et Lodash, que vous compariez des tableaux ou des objets, cela ressemble à ceci:

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean
170
Jason Boerner

Je pense que c'est la manière la plus simple de le faire en utilisant JSON stringify, et que cela peut être la meilleure solution dans certaines situations:

JSON.stringify(a1) === JSON.stringify(a2);

Ceci convertit les objets a1 et a2 en chaînes afin de pouvoir les comparer. L'ordre est important dans la plupart des cas, car cela permet de trier l'objet à l'aide d'un algorithme de tri indiqué dans l'une des réponses ci-dessus.

Veuillez noter que vous ne comparez plus l'objet, mais la représentation sous forme de chaîne de l'objet. Ce n'est peut-être pas exactement ce que vous voulez.

81
radtek

Ce que vous entendez par "identique" n'est pas clair. Par exemple, les tableaux a et b ci-dessous sont-ils identiques (notez les tableaux imbriqués)?

var a = ["foo", ["bar"]], b = ["foo", ["bar"]];

Voici une fonction de comparaison de tableau optimisée qui compare successivement les éléments correspondants de chaque tableau en utilisant une égalité stricte et ne fait pas de comparaison récursive d'éléments de tableau qui sont eux-mêmes des tableaux, ce qui signifie que pour l'exemple ci-dessus, arraysIdentical(a, b) renverrait false. Cela fonctionne dans le cas général, ce que les solutions basées sur JSON et join()- ne:

function arraysIdentical(a, b) {
    var i = a.length;
    if (i != b.length) return false;
    while (i--) {
        if (a[i] !== b[i]) return false;
    }
    return true;
};
61
Tim Down

Dans l'esprit de la question initiale:

Je voudrais comparer deux tableaux ... idéalement, efficacement. Rien fantaisie, juste vrai si elles sont identiques, et faux sinon.

J'ai effectué des tests de performance sur certaines des suggestions les plus simples proposées ici avec les résultats } _ (rapide à lent) suivants:

while (67%) de Tim Down

var i = a1.length;
while (i--) {
    if (a1[i] !== a2[i]) return false;
}
return true

tous (69%) par l'utilisateur2782196

a1.every((v,i)=> v === a2[i]);

réduire (74%) par les DEI

a1.reduce((a, b) => a && a2.includes(b), true);

rejoindre & toString (78%) par Gaizka Allende & vivek

a1.join('') === a2.join('');

a1.toString() === a2.toString();

half toString (90%) de Victor Palomo

a1 == a2.toString();

stringify (100%) de radtek

JSON.stringify(a1) === JSON.stringify(a2);

Remarque Les exemples ci-dessous supposent que les tableaux sont des tableaux tri-dimensionnels triés. La comparaison .length a été supprimée pour un repère commun (ajoutez a1.length === a2.length à l'une des suggestions et vous obtiendrez un gain de performances d'environ 10%). Choisissez les solutions qui vous conviennent le mieux, en connaissant la vitesse et les limites de chacune.

Note non liée: il est intéressant de voir des gens obtenir John Waynes heureux de la gâchette sur le bouton de vote à la baisse pour des réponses parfaitement légitimes à cette question. 

35
unitario

En me basant sur la réponse de Tomáš Zato, je conviens que le plus rapide est de parcourir les tableaux. De plus (comme d'autres l'ont déjà indiqué), la fonction doit être appelée égale/égale, et non pas comparer. À la lumière de cela, j’ai modifié la fonction pour gérer les tableaux de comparaison de similarité - c’est-à-dire qu’ils ont les mêmes éléments, mais hors d’ordre - pour un usage personnel, et que je pensais que je le lirais ici à la vue de tous.

Array.prototype.equals = function (array, strict) {
    if (!array)
        return false;

    if (arguments.length == 1)
        strict = true;

    if (this.length != array.length)
        return false;

    for (var i = 0; i < this.length; i++) {
        if (this[i] instanceof Array && array[i] instanceof Array) {
            if (!this[i].equals(array[i], strict))
                return false;
        }
        else if (strict && this[i] != array[i]) {
            return false;
        }
        else if (!strict) {
            return this.sort().equals(array.sort(), true);
        }
    }
    return true;
}

Cette fonction prend un paramètre additionnel de strict qui par défaut est true. Ce paramètre strict définit si les tableaux doivent être totalement égaux en contenu et en ordre de contenu, ou tout simplement contenir le même contenu.

Exemple:

var arr1 = [1, 2, 3, 4];
var arr2 = [2, 1, 4, 3];  // Loosely equal to 1
var arr3 = [2, 2, 3, 4];  // Not equal to 1
var arr4 = [1, 2, 3, 4];  // Strictly equal to 1

arr1.equals(arr2);         // false
arr1.equals(arr2, false);  // true
arr1.equals(arr3);         // false
arr1.equals(arr3, false);  // false
arr1.equals(arr4);         // true
arr1.equals(arr4, false);  // true

J'ai aussi écrit un rapide jsfiddle avec la fonction et cet exemple:
http://jsfiddle.net/Roundaround/DLkxX/

28
Evan Steinkerchner

Même si cela a beaucoup de réponses, une que je crois être utile:

const newArray = [ ...new Set( [...arr1, ...arr2] ) ]

Il n’est pas indiqué dans la question à quoi ressemblera la structure du tableau, donc si vous savez avec certitude que vous n’aurez ni tableaux ni objets imbriqués dans votre tableau (c’est arrivé à moi, c’est pourquoi Je suis venu à cette réponse) le code ci-dessus va fonctionner.

Ce qui se passe, c’est que nous utilisons opérateur de propagation (...) pour concaténer les deux tableaux, puis nous utilisons Set pour éliminer les doublons. Une fois que vous avez cela, vous pouvez comparer leurs tailles. Si les trois tableaux ont la même taille, vous êtes prêt à partir.

Cette réponse ignore également l'ordre des éléments, comme je l'ai dit, la situation exacte m'est arrivée, alors peut-être que quelqu'un dans la même situation pourrait se retrouver ici (comme je l'ai fait).


Edit1.

Répondant à la question de Dmitry Grinko: "Pourquoi avez-vous utilisé l'opérateur de diffusion (...) ici - ... nouvel ensemble? Cela ne fonctionne pas"

Considérons ce code:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Tu auras

[ Set { 'a', 'b', 'c' } ]

Afin de travailler avec cette valeur, vous devez utiliser certaines propriétés Set (voir https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ) . D'autre part, lorsque vous utilisez ce code:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Tu auras

[ 'a', 'b', 'c' ]

C'est la différence, le premier me donnerait un ensemble, cela fonctionnerait aussi car je pourrais obtenir la taille de cet ensemble, mais le dernier me donne le tableau dont j'ai besoin, ce qui est plus direct à la résolution.

8

Sur les mêmes lignes que JSON.encode, utilisez join ().

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    //slice so we do not effect the original
    //sort makes sure they are in order
    //join makes it a string so we can do a string compare
    var cA = arrA.slice().sort().join(","); 
    var cB = arrB.slice().sort().join(",");

    return cA===cB;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];  //will return true

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //true

Le seul problème est que si vous vous souciez de types que la dernière comparaison teste ... Si vous vous souciez de types, vous devrez boucler.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;

    //slice so we do not effect the orginal
    //sort makes sure they are in order
    var cA = arrA.slice().sort(); 
    var cB = arrB.slice().sort();

    for(var i=0;i<cA.length;i++){
         if(cA[i]!==cB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false

Si l'ordre doit rester le même, alors qu'il ne s'agit que d'une boucle, aucun tri n'est nécessaire.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    for(var i=0;i<arrA.length;i++){
         if(arrA[i]!==arrB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,a) );  //true
console.log( checkArrays(a,b) );  //false
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false
7
epascarello

Si ce ne sont que deux tableaux de nombres ou de chaînes, il s’agit d’un rapide d'une ligne

const array1 = [1, 2, 3];
const array2 = [1, 3, 4];
console.log(array1.join(',') === array2.join(',')) //false

const array3 = [1, 2, 3];
const array4 = [1, 2, 3];
console.log(array3.join(',') === array4.join(',')) //true
6
Gaizka Allende

pour un tableau à une dimension, vous pouvez simplement utiliser:

arr1.sort().toString() == arr2.sort().toString()

cela prendra également soin de tableau avec index mal assorti.

5
Vivek

Si vous utilisez un framework de test tel que Mocha avec la bibliothèque Chai assertion, vous pouvez utiliser deep equal pour comparer des tableaux.

expect(a1).to.deep.equal(a2)

Cela ne devrait être vrai que si les tableaux ont des éléments égaux aux indices correspondants.

5
metakermit

Voici une version TypeScript:

//https://stackoverflow.com/a/16436975/2589276
export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean {
    if (a === b) return true
    if (a == null || b == null) return false
    if (a.length != b.length) return false

    for (var i = 0; i < a.length; ++i) {
        if (a[i] !== b[i]) return false
    }
    return true
}

//https://stackoverflow.com/a/16436975/2589276
export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {
    return JSON.stringify(a) === JSON.stringify(b)
}

Quelques cas de test pour le moka:

it('arraysEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','Apple','banana']
    let f = ['car','Apple','banana']
    let g = ['car','Apple','banan8']

    expect(arraysEqual(a, b)).to.equal(true)
    expect(arraysEqual(c, d)).to.equal(true)
    expect(arraysEqual(a, d)).to.equal(false)
    expect(arraysEqual(e, f)).to.equal(true)
    expect(arraysEqual(f, g)).to.equal(false)
})

it('arraysDeepEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','Apple','banana']
    let f = ['car','Apple','banana']
    let g = ['car','Apple','banan8']
    let h = [[1,2],'Apple','banan8']
    let i = [[1,2],'Apple','banan8']
    let j = [[1,3],'Apple','banan8']

    expect(arraysDeepEqual(a, b)).to.equal(true)
    expect(arraysDeepEqual(c, d)).to.equal(true)
    expect(arraysDeepEqual(a, d)).to.equal(false)
    expect(arraysDeepEqual(e, f)).to.equal(true)
    expect(arraysDeepEqual(f, g)).to.equal(false)
    expect(arraysDeepEqual(h, i)).to.equal(true)
    expect(arraysDeepEqual(h, j)).to.equal(false)
})
4
Esqarrouth

Ceci compare 2 tableaux non triés:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}

Herer ma solution:

/**
 * Tests two data structures for equality
 * @param {object} x
 * @param {object} y
 * @returns {boolean}
 */
var equal = function(x, y) {
    if (typeof x !== typeof y) return false;
    if (x instanceof Array && y instanceof Array && x.length !== y.length) return false;
    if (typeof x === 'object') {
        for (var p in x) if (x.hasOwnProperty(p)) {
            if (typeof x[p] === 'function' && typeof y[p] === 'function') continue;
            if (x[p] instanceof Array && y[p] instanceof Array && x[p].length !== y[p].length) return false;
            if (typeof x[p] !== typeof y[p]) return false;
            if (typeof x[p] === 'object' && typeof y[p] === 'object') { if (!equal(x[p], y[p])) return false; } else
            if (x[p] !== y[p]) return false;
        }
    } else return x === y;
    return true;
};

Fonctionne avec toutes les structures de données imbriquées et ignore évidemment les méthodes des objets. Ne pensez même pas à étendre Object.prototype avec cette méthode, quand j'ai essayé cette fois, jQuery s'est cassé;)

Pour la plupart des baies, il est toujours plus rapide que la plupart des solutions de sérialisation. C'est probablement la méthode de comparaison la plus rapide pour les tableaux d'enregistrements d'objet.

3
Harry

Nous pourrions faire cela de manière fonctionnelle, en utilisant every ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every )

function compareArrays(array1, array2) {
    if (array1.length === array2.length)
        return array1.every((a, index) => a === array2[index])
    else
        return false
}

// test
var a1 = [1,2,3];
var a2 = [1,2,3];

var a3 = ['a', 'r', 'r', 'a', 'y', '1']
var a4 = ['a', 'r', 'r', 'a', 'y', '2']

console.log(compareArrays(a1,a2)) // true
console.log(compareArrays(a1,a3)) // false
console.log(compareArrays(a3,a4)) // false
3
peonicles
var a1 = [1,2,3,6];
var a2 = [1,2,3,5];

function check(a, b) {
  return (a.length != b.length) ? false : 
  a.every(function(row, index) {
    return a[index] == b[index];
  });
}  

check(a1, a2);

////// OR ///////

var a1 = [1,2,3,6];
var a2 = [1,2,3,6];

function check(a, b) {
  return (a.length != b.length) ? false : 
  !(a.some(function(row, index) {
    return a[index] != b[index];
  }));
}  

check(a1, a2)
2
Vasanth

Je crois en la simplicité JS et avec ECMAScript 2015, ce qui est doux et simple à comprendre.

var is_arrays_compare_similar = function (array1, array2) {

    let flag = true;

    if (array1.length == array2.length) {

        // check first array1 object is available in array2 index
        array1.every( array_obj => {
            if (flag) {
                if (!array2.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        // then vice versa check array2 object is available in array1 index
        array2.every( array_obj => {
            if (flag) {
                if (!array1.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        return flag;
    } else {
        return false;
    }

}

espérons que cela aidera quelqu'un.

1
ArifMustafa

Comparer 2 tableaux:

var arr1 = [1,2,3];
var arr2 = [1,2,3];

function compare(arr1,arr2)
{
  if((arr1 == arr2) && (arr1.length == arr2.length))
    return true;
  else
    return false;
}

fonction d'appel

var isBool = compare(arr1.sort().join(),arr2.sort().join());
1
Amay Kulkarni

Choisissez chacun de [a] et passez en boucle de [b]: Résultat: 1, 5

var a = [1,4,5,9];
var b = [1,6,7,5];

for (i = 0; i < a.length; i++) {
    for (z = 0; z < a.length; z++) {
        if (a[i] === b[z]) {
            console.log(b[z]); // if match > console.log it 
        }
    }
}
1
jclobro

La raison en est que l’identité ou l’opérateur strict (===) ne se compare à aucune conversion de type, ce qui signifie que si les deux valeurs n’ont pas la même valeur et le même type, elles ne seront pas considérées comme égales.

jetez un oeil à ce lien, il vous évite le doute un moyen facile de comprendre le fonctionnement de l'opérateur d'identité

1
ludico8

ce script compare l'objet, les tableaux et le tableau multidimensionnel

function compare(a,b){
     var primitive=['string','number','boolean'];
     if(primitive.indexOf(typeof a)!==-1 && primitive.indexOf(typeof a)===primitive.indexOf(typeof b))return a===b;
     if(typeof a!==typeof b || a.length!==b.length)return false;
     for(i in a){
          if(!compare(a[i],b[i]))return false;
     }
     return true;
}

la première ligne vérifie s'il s'agit d'un type primitif. si c'est le cas, il compare les deux paramètres.

si ce sont des objets. itère sur l'objet et vérifie chaque élément de manière récursive. 

Usage:

var a=[1,2,[1,2]];
var b=[1,2,[1,2]];
var isEqual=compare(a,b);  //true
1
Omar Elawady

Cette fonction compare deux tableaux de forme et de diversité arbitraires:

function equals(a1, a2) {

    if (!Array.isArray(a1) || !Array.isArray(a2)) {
        throw new Error("Arguments to function equals(a1, a2) must be arrays.");
    }

    if (a1.length !== a2.length) {
        return false;
    }

    for (var i=0; i<a1.length; i++) {
        if (Array.isArray(a1[i]) && Array.isArray(a2[i])) {
            if (equals(a1[i], a2[i])) {
                continue;
            } else {
                return false;
            }
        } else {
            if (a1[i] !== a2[i]) {
                return false;
            }
        }
    }

    return true;
}
1
chessweb

Votre code ne traitera pas le cas correctement lorsque les deux tableaux ont les mêmes éléments mais pas dans le même ordre.

Regardez mon code avec votre exemple qui compare deux tableaux dont les éléments sont des nombres, vous pouvez le modifier ou l'étendre pour d'autres types d'élément (en utilisant .join () au lieu de .toString ()).

var a1 = [1,2,3];
var a2 = [1,2,3];
const arraysAreEqual = a1.sort().toString()==a2.sort().toString();
// true if both arrays have same elements else false
console.log(arraysAreEqual);
1
durga patra

Dans mon cas, les tableaux comparés ne contiennent que des nombres et des chaînes. Cette fonction vous indiquera si les tableaux contiennent les mêmes éléments.

function are_arrs_match(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_match(arr1, arr2)) //true
console.log (are_arrs_match(arr1, arr3)) //false
1
yesnik

Extension de l'idée de Tomáš Zato. Tomas's Array.prototype.compare devrait être appelé Array.prototype.compareIdentical.

Cela passe:

[1, 2, [3, 4]].compareIdentical ([1, 2, [3, 2]]) === false;
[1, "2,3"].compareIdentical ([1, 2, 3]) === false;
[1, 2, [3, 4]].compareIdentical ([1, 2, [3, 4]]) === true;
[1, 2, 1, 2].compareIdentical ([1, 2, 1, 2]) === true;

Mais échoue sur:

[[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]])

Voici la meilleure version (à mon avis):

Array.prototype.compare = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time
    if (this.length != array.length)
        return false;

    this.sort();
    array.sort();
    for (var i = 0; i < this.length; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].compare(array[i]))
                return false;
        }
        else if (this[i] != array[i]) {
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;
        }
    }
    return true;
}

http://jsfiddle.net/igos/bcfCY/

1
Igor S.

Une autre approche avec très peu de code (en utilisant Array réduire et Array inclut ):

arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true)

Si vous souhaitez également comparer l'égalité d'ordre:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • La vérification length garantit que l'ensemble des éléments d'un tableau n'est pas simplement un sous-ensemble de l'autre.

  • Le réducteur est utilisé pour parcourir un tableau et rechercher chaque élément dans un autre tableau. Si un élément n'est pas trouvé, la fonction de réduction renvoie false

    1. Dans le premier exemple, il est testé qu'un élément est inclus
    2. Le deuxième exemple vérifie aussi la commande
1
DEls
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.Push(collection[i]) : null

Voici comment je l'ai fait.

1
Leed

Avec une option pour comparer la commande ou non:

function arraysEqual(a1, a2, compareOrder) {
    if (a1.length !== a2.length) {
        return false;
    }

    return a1.every(function(value, index) {
        if (compareOrder) {
            return value === a2[index];
        } else {
            return a2.indexOf(value) > -1;
        }
    });
}
0
Lacho Tomov

Récursif & fonctionne surIMBRIQU&EACUTE;tableaux:

function ArrEQ(a1,a2){
   return( 
        //:Are both elements arrays?
        Array.isArray(a1)&&Array.isArray(a2) 
        ?
        //:Yes: Test each entry for equality:
        a1.every((v,i)=>(ArrEQ(v,a2[i])))
        :
        //:No: Simple Comparison:
        (a1===a2)
   );;
};;

console.log( "Works With Nested Arrays:" );
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]],
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]]
));;     
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"DIFFERENT:APPLES" ]]],
    [1,2,3,[4,5,[6,"DIFFERENT:ORANGES"]]]
));;  
0
J.M.I. MADISON
In a simple way uning stringify but at same time thinking in complex arrays:

**Simple arrays**:  
var a = [1,2,3,4];  
var b = [4,2,1,4];  
JSON.stringify(a.sort()) === JSON.stringify(b.sort()) // true  

**Complex arrays**:  
var a = [{id:5,name:'as'},{id:2,name:'bes'}];  
var b = [{id:2,name:'bes'},{id:5,name:'as'}];  
JSON.stringify(a.sort(function(a,b) {return a.id - b.id})) === JSON.stringify(b.sort(function(a,b) {return a.id - b.id})) // true  

**Or we can create a sort function**  

function sortX(a,b) {  
return a.id -b.id; //change for the necessary rules  
}  
JSON.stringify(a.sort(sortX)) === JSON.stringify(b.sort(sortX)) // true  
0
Pedro Bustamante

Une approche simple:

function equals(a, b) {
    if ((a && !b) || (!a && b) || (!a && !b) || (a.length !== b.length)) {
        return false;
    }

    var isDifferent = a.some(function (element, index) { 
        return element !== b[index];
    });

    return !isDifferent;
}
0
Pedro Rodrigues

Ma solution compare les objets, pas les tableaux. Cela fonctionnerait de la même manière que Tomáš en tant que tableaux sont des objets, mais sans l'avertissement

Object.prototype.compare_to = function(comparable){

    // Is the value being compared an object
    if(comparable instanceof Object){

        // Count the amount of properties in @comparable
        var count_of_comparable = 0;
        for(p in comparable) count_of_comparable++;

        // Loop through all the properties in @this
        for(property in this){

            // Decrements once for every property in @this
            count_of_comparable--;

            // Prevents an infinite loop
            if(property != "compare_to"){

                // Is the property in @comparable
                if(property in comparable){

                    // Is the property also an Object
                    if(this[property] instanceof Object){

                        // Compare the properties if yes
                        if(!(this[property].compare_to(comparable[property]))){

                            // Return false if the Object properties don't match
                            return false;
                        }
                    // Are the values unequal
                    } else if(this[property] !== comparable[property]){

                        // Return false if they are unequal
                        return false;
                    }
                } else {

                    // Return false if the property is not in the object being compared
                    return false;
                }
            }
        }
    } else {

        // Return false if the value is anything other than an object
        return false;
    }

    // Return true if their are as many properties in the comparable object as @this
    return count_of_comparable == 0;
}

J'espère que cela vous aidera, vous ou toute autre personne à la recherche d'une réponse.

0
user1877408

Fonction récursive cmp travaillant avec number/string/array/object

<script>
var cmp = function(element, target){

   if(typeof element !== typeof target)
   {
      return false;
   }
   else if(typeof element === "object" && (!target || !element))
   {
      return target === element;
   }
   else if(typeof element === "object")
   {
       var keys_element = Object.keys(element);
       var keys_target  = Object.keys(target);
       
       if(keys_element.length !== keys_target.length)
       {
           return false;
       }
       else
       {
           for(var i = 0; i < keys_element.length; i++)
           {
                if(keys_element[i] !== keys_target[i])
                    return false;
                if(!cmp(element[keys_element[i]], target[keys_target[i]]))
                    return false;
           }
                   return true;
       }
   }
   else
   {
           return element === target;

   }
};

console.log(cmp({
    key1: 3,
    key2: "string",
    key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]
}, {
    key1: 3,
    key2: "string",
    key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]
})); // true

console.log(cmp({
    key1: 3,
    key2: "string",
    key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]
}, {
    key1: 3,
    key2: "string",
    key3: [4, "45", {key4: [5, "6", undefined, null, {v:1}]}]
})); // false
</script>
0
Daphoque

essayé deep-égal et cela a fonctionné

var eq = require('deep-equal');
eq({a: 1, b: 2, c: [3, 4]}, {c: [3, 4], a: 1, b: 2});
0
d9k
function compareArrays(arrayA, arrayB) {
    if (arrayA.length != arrayB.length) return true;
    for (i = 0; i < arrayA.length; i++)
        if (arrayB.indexOf(arrayA[i]) == -1) {
            return true;
        }
    }
    for (i = 0; i < arrayB.length; i++) {
        if (arrayA.indexOf(arrayB[i]) == -1) {
            return true;
        }
    }
    return false;
}
0
macki

Fonctionne avecPLUSIEURSarguments avecIMBRIQU&EACUTE;Stableaux:

//:Return true if all of the arrays equal.
//:Works with nested arrays.
function AllArrEQ(...arrays){
    for(var i = 0; i < (arrays.length-1); i++ ){
        var a1 = arrays[i+0];
        var a2 = arrays[i+1];
        var res =( 
            //:Are both elements arrays?
            Array.isArray(a1)&&Array.isArray(a2) 
            ?
            //:Yes: Compare Each Sub-Array:
            //:v==a1[i]
            a1.every((v,i)=>(AllArrEQ(v,a2[i])))
            :
            //:No: Simple Comparison:
            (a1===a2)
        );;
        if(!res){return false;}
    };;
    return( true );
};;

console.log( AllArrEQ( 
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
));; 
0
J.M.I. MADISON

J'ai utilisé: pour joindre un tableau et créer une chaîne à comparer . Pour les scénarios complexes que cet exemple, vous pouvez utiliser un autre séparateur.

var a1 = [1,2,3];
var a2 = [1,2,3];
if (a1.length !== a2.length) {
   console.log('a1 and a2 are not equal')
}else if(a1.join(':') === a2.join(':')){
   console.log('a1 and a2 are equal')
}else{
   console.log('a1 and a2 are not equal')
}
0
Manoj Yadav

Bien que la réponse principale à cette question soit correcte et correcte, le code fourni pourrait être amélioré.

Vous trouverez ci-dessous mon propre code permettant de comparer des tableaux et des objets. Le code est court et simple:

Array.prototype.equals = function(otherArray) {
  if (!otherArray || this.length != otherArray.length) return false;
  return this.reduce(function(equal, item, index) {
    var otherItem = otherArray[index];
    var itemType = typeof item, otherItemType = typeof otherItem;
    if (itemType !== otherItemType) return false;
    return equal && (itemType === "object" ? item.equals(otherItem) : item === otherItem);
  }, true);
};

if(!Object.prototype.keys) {
  Object.prototype.keys = function() {
    var a = [];
    for (var key in this) {
      if (this.hasOwnProperty(key)) a.Push(key);
    }
    return a;
  }
  Object.defineProperty(Object.prototype, "keys", {enumerable: false});
}

Object.prototype.equals = function(otherObject) {
  if (!otherObject) return false;
  var object = this, objectKeys = object.keys();
  if (!objectKeys.equals(otherObject.keys())) return false;
  return objectKeys.reduce(function(equal, key) {
    var value = object[key], otherValue = otherObject[key];
    var valueType = typeof value, otherValueType = typeof otherValue;
    if (valueType !== otherValueType) return false;
    // this will call Array.prototype.equals for arrays and Object.prototype.equals for objects
    return equal && (valueType === "object" ? value.equals(otherValue) : value === otherValue);
  }, true);
}
Object.defineProperty(Object.prototype, "equals", {enumerable: false});

Ce code prend en charge les tableaux imbriqués dans les objets et les objets imbriqués dans les tableaux.

Vous pouvez voir une suite complète de tests et tester le code vous-même à l'adresse suivante: https://repl.it/Esfz/3

0
Mator

Voici une version de CoffeeScript, pour ceux qui préfèrent cela:

Array.prototype.equals = (array) ->
  return false if not array # if the other array is a falsy value, return
  return false if @length isnt array.length # compare lengths - can save a lot of time

  for item, index in @
    if item instanceof Array and array[index] instanceof Array # Check if we have nested arrays
      if not item.equals(array[index]) # recurse into the nested arrays
        return false
    else if this[index] != array[index]
      return false # Warning - two different object instances will never be equal: {x:20} != {x:20}
  true

Tous les crédits vont à @ tomas-zato.

0
Martin

En fait, dans la Lodashdocumentation , ils donnent deux assez bons exemples pour comparer et renvoyer des tableaux frais pour les différences et les similitudes (respectivement dans les exemples ci-dessous):

import { differenceWith, intersectionWith, isEqual } from 'lodash'

differenceWith(
  [{ a: 1 }, { b: 1 }],
  [{ a: 1 }, { b: 1 }, { c: 1 }],
  isEqual
) // []... ????the bigger array needs to go first!

differenceWith(
  [{ a: 1 }, { b: 1 }, { c: 1 }],
  [{ a: 1 }, { b: 1 }],
  isEqual,
) // [{ c: 1 }] ????

intersectionWith(
  [{ a: 1 }, { b: 1 }],
  [{ a: 1 }, { b: 1 }, { c: 1 }],
  isEqual,
) // [{ a: 1 }, { b: 1 }] ????this one doesn't care about which is bigger

Si vous ne savez pas toujours quel tableau sera le plus grand, vous pouvez écrire une fonction d'assistance pour cela:

const biggerFirst = (arr1, arr2) => {
  return arr1.length > arr2.length ? [arr1, arr2] : [arr2, arr1]
}

const [big, small] = biggerFirst(
  [{ a: 1 }, { b: 1 }],
  [{ a: 1 }, { b: 1 }, { c: 1 }],
)

differenceWith(big, small, isEqual) // ????even though we have no idea which is bigger when they are fed to biggerFirst()

D'après ce que je peux dire, ceux-ci vont bien aussi, donc c'est joli, Nice.

Je sais qu’il ne faut pas applaudir aux bibliothèques pour tout, mais c’est la solution la plus concise/propre que j’ai trouvée à un problème très courant. J'espère que ça aide quelqu'un!

0
corysimmons

Voici un moyen très court de le faire

function arrEquals(arr1, arr2){
     arr1.length == arr2.length && 
     arr1.filter(elt=>arr2.includes(elt)).length == arr1.length
}
0
Nkemtakeh Celsoppe

Déjà quelques bonnes réponses.Mais j'aimerais partager une autre idée qui s'est révélée fiable pour comparer des tableaux. Nous pouvons comparer deux tableaux en utilisant JSON.stringify () . Il créera une chaîne dans le tableau et comparera ainsi deux chaînes obtenues à partir de deux tableaux pour égalité.

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:1},2]) //true

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},2]) //false

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:1},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //true

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[4]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[5]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //true
0
AL-zami

Si le tableau est simple et que l'ordre est important, ces deux lignes peuvent aider

//Assume
var a = ['a','b', 'c']; var b = ['a','e', 'c'];  

if(a.length !== b.length) return false;
return !a.reduce(
  function(prev,next,idx, arr){ return prev || next != b[idx] },false
); 

Réduit les passages dans un tableau et renvoie 'false' si au moins un élément de 'a' n'est pas équivalent à un élément de 'b' .__ 

0
Serge