Comment savoir si deux tableaux ont les mêmes valeurs


105

J'ai ces deux tableaux: l'un est rempli d'informations provenant d'une requête ajax et un autre stocke les boutons sur lesquels l'utilisateur clique. J'utilise ce code (j'ai rempli des exemples de numéros):

var array1 = [2, 4];
var array2 = [4, 2]; //It cames from the user button clicks, so it might be disordered.
array1.sort(); //Sorts both Ajax and user info.
array2.sort();
if (array1==array2) {
    doSomething();
}else{
    doAnotherThing();
}

Mais ça donne toujours false, même si les deux tableaux sont identiques, mais avec un nom différent. (J'ai vérifié cela dans la console JS de Chrome). Alors, y a-t-il un moyen de savoir si ces deux tableaux contiennent le même? Pourquoi donne-t-il false? Comment puis-je savoir quelles valeurs du premier tableau ne figurent pas dans le second?


1
Je suis presque certain que vous devez parcourir chaque élément des tableaux.
Thomas Li

Savez-vous pourquoi il renvoie faux? Curieuse.
RobW


Réponses:


36
function arraysEqual(_arr1, _arr2) {

    if (!Array.isArray(_arr1) || ! Array.isArray(_arr2) || _arr1.length !== _arr2.length)
      return false;

    var arr1 = _arr1.concat().sort();
    var arr2 = _arr2.concat().sort();

    for (var i = 0; i < arr1.length; i++) {

        if (arr1[i] !== arr2[i])
            return false;

    }

    return true;

}

Notez que cela ne modifie pas les tableaux d'origine contrairement à une réponse précédente.


2
le tri prend nlog (n) temps. Vous n'avez pas besoin de tri. Cette réponse stackoverflow.com/a/55614659/3209523 fonctionne en temps linéaire.
canbax

L'utilisation de typographie Array.isArray () provoquait des erreurs, supprimant cela fonctionnait bien.
Ariel Frischer le

89

Si les éléments de votre tableau ne sont pas des objets - s'il s'agit de nombres ou de chaînes, par exemple, vous pouvez comparer leurs chaînes jointes pour voir s'ils ont les mêmes membres dans n'importe quel ordre -

var array1= [10, 6, 19, 16, 14, 15, 2, 9, 5, 3, 4, 13, 8, 7, 1, 12, 18, 11, 20, 17];
var array2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];

if(array1.sort().join(',')=== array2.sort().join(',')){
    alert('same members');
}
else alert('not a match');

2
Cela fonctionnera bien pour les primitives ou les objets qui ont des valeurs toString identifiant de manière unique, mais pas pour n'importe quel objet.
devios1

Merci! solution soignée
Gaston Sanchez

3
Méfiez-vous des éléments nuls et du tri. Je me suis retrouvé dans mon cas avec des chaînes à comparer comme ", 2,2,3" et "2,2,3", qui bien sûr ne sont pas strictement égales.
barbara.post

2
Pourrait échouer pour les chaînes, c'est ['a', 'b']-à- dire et ['a,b']. Je ne recommanderais cette technique que pour les petits scripts jetables.
alex

1
@alex - dans mon cas, les virgules sont autorisées dans les chaînes mais pas les points-virgules, donc j'ai utilisé ';' pour rejoindre au lieu de virgule
a2345sooted

45

Si vous souhaitez vérifier uniquement si deux tableaux ont les mêmes valeurs (quels que soient le nombre d'occurrences et l'ordre de chaque valeur), vous pouvez le faire en utilisant lodash :

_.isEmpty(_.xor(array1, array2))

Bref, simple et joli!


1
Je n'arrive pas à trouver xordans les documents de soulignement? Pensez-vous à IODash?
Patrick Mencias-lewis

44
Array.prototype.compare = function(testArr) {
    if (this.length != testArr.length) return false;
    for (var i = 0; i < testArr.length; i++) {
        if (this[i].compare) { //To test values in nested arrays
            if (!this[i].compare(testArr[i])) return false;
        }
        else if (this[i] !== testArr[i]) return false;
    }
    return true;
}

var array1 = [2, 4];
var array2 = [4, 2];
if(array1.sort().compare(array2.sort())) {
    doSomething();
} else {
    doAnotherThing();
}

Peut être?


Je vous remercie! Cela fonctionne comme vous le souhaitez. J'ai un peu modifié la fonction pour savoir aussi combien il y a de discordances.
Carlos Precioso

faux pour [2,4] [4,2].
Suraz Khanal

@SurazKhanal Encore besoin de trier
Aaron McMillin

27

Pourquoi votre code n'a pas fonctionné

JavaScript a des types de données primitifs et des types de données non primitifs.

Pour les types de données primitifs, ==et ===vérifiez si les éléments de chaque côté des barres ont la même valeur. C'est pourquoi 1 === 1c'est vrai.

Pour les types de données non primitifs tels que les tableaux, ==et ===vérifiez l'égalité des références. Autrement dit, ils vérifient si arr1etarr2 sont le même objet. Dans votre exemple, les deux tableaux ont les mêmes objets dans le même ordre, mais ne sont pas équivalents.

Solutions

Deux tableaux, arr1et arr2, ont les mêmes membres si et seulement si:

  • Tout arr2est dedansarr1

ET

  • Tout arr1est dedansarr2

Cela fera donc l'affaire (ES2016):

const containsAll = (arr1, arr2) => 
                arr2.every(arr2Item => arr1.includes(arr2Item))

const sameMembers = (arr1, arr2) => 
                        containsAll(arr1, arr2) && containsAll(arr2, arr1);

sameMembers(arr1, arr2); // `true`

Cette deuxième solution utilisant Underscore est plus proche de ce que vous essayiez de faire:

arr1.sort();
arr2.sort();

_.isEqual(arr1, arr2); // `true`

Cela fonctionne parce qu'il isEqualvérifie «l'égalité profonde», ce qui signifie qu'il regarde plus que simplement l'égalité de référence et compare les valeurs.

Une solution à votre troisième question

Vous avez également demandé comment savoir dans quels éléments arr1ne sont pas contenus arr2.

Cela le fera (ES2015):

const arr1 = [1, 2, 3, 4];
const arr2 = [3, 2, 1];

arr1.filter(arr1Item => !arr2.includes(arr1Item)); // `[4]`

Vous pouvez également utiliser la differenceméthode Underscore :

_.difference(arr1, arr2); // `[4]`

METTRE À JOUR

Voir le commentaire de @ Redu - ma solution est pour sameMembers, mais ce que vous pouvez avoir à l'esprit est sameMembersInOrderégalement connu sous le nom de deepEquals.

MISE À JOUR 2

Si vous ne vous souciez pas de l'ordre des membres des tableaux, ES2015 + Setpeut être une meilleure structure de données que Array. Consultez les notes MDN sur la façon d'implémenter isSupersetet d'difference utiliser des correctifs dangereux pour les singes.


1
Vos solutions sont fausses. "Deux tableaux, arr1 et arr2, ont les mêmes membres si et seulement si: Tout dans arr2 est dans arr1 ET Tout dans arr1 est dans arr2" c'est également faux. Ceci est un tableau et non un ensemble. Donc sameMembers([1,1,2],[2,1,2]);devrait retourner false.
Rédu

1
@Redu suppose que cela dépend de ce que signifie «mêmes membres» - je suppose que cela signifie «a les mêmes membres». sameMembers([1,1,2],[2,1,2])devrait revenir true, à mon avis. sameMembersInOrder([1,1,2],[2,1,2])AKA deepEquals([1,1,2],[2,1,2])devrait revenir false.
Max Heiber

Votre troisième solution arr1.filter...ne fonctionnera que pour vérifier si arr2 a tous les éléments de arr1 ou non, mais pas l'inverse qui est également nécessaire.
Aakash Verma

10

Vérification de l'égalité des objets:JSON.stringify(array1.sort()) === JSON.stringify(array2.sort())

Le test ci-dessus fonctionne également avec des tableaux d'objets, auquel cas utilisez une fonction de tri comme documenté dans http://www.w3schools.com/jsref/jsref_sort.asp

Cela peut suffire pour les petits tableaux avec des schémas JSON plats.


9

Notre objectif est essentiellement de vérifier si 2 tableaux sont des ensembles égaux. set est l' ensemble défini mathématiquement . Le tri le plus rapide prend asymptotiquement le temps O (nlog (n)) . Donc, si vous triez un tableau, cela prendrait au moins O (nlog (n)) temps. Mais vous pouvez effectuer cette tâche plus rapidement , ce qui prend asymptotiquement un temps O (n) (cas moyen et non pire cas) avec une structure de données de dictionnaire. Dans JS, un dictionnaire est simplement un objet avec des clés et des valeurs.

/** assumes array elements are primitive types
* check whether 2 arrays are equal sets.
* @param  {} a1 is an array
* @param  {} a2 is an array
*/
function areArraysEqualSets(a1, a2) {
  const superSet = {};
  for (const i of a1) {
    const e = i + typeof i;
    superSet[e] = 1;
  }

  for (const i of a2) {
    const e = i + typeof i;
    if (!superSet[e]) {
      return false;
    }
    superSet[e] = 2;
  }

  for (let e in superSet) {
    if (superSet[e] === 1) {
      return false;
    }
  }

  return true;
}

Notez que cette fonction fonctionne avec des tableaux de types primitifs et suppose a1et a2sont des tableaux.


5

Et ça? ES 2017 je suppose:

const array1 = [1, 3, 5];
const array2 = [1, 5, 3];

const isEqual = (array1.length === array2.length) && (array1.every(val => array2.includes(val)));
console.log(isEqual);

La première condition vérifie si les deux tableaux ont la même longueur et la deuxième condition vérifie si le premier tableau est un sous-ensemble du deuxième tableau. La combinaison de ces 2 conditions devrait alors aboutir à la comparaison de tous les éléments des 2 tableaux quel que soit l'ordre des éléments.

Le code ci-dessus ne fonctionnera que si les deux tableaux ont des éléments non dupliqués.


3

Lorsque vous comparez ces deux tableaux, vous comparez les objets qui représentent les tableaux, pas le contenu.

Vous devrez utiliser une fonction pour comparer les deux. Vous pouvez écrire le vôtre qui boucle simplement l'un et le compare à l'autre après avoir vérifié que les longueurs sont les mêmes.


3

Solution simple pour une égalité superficielle en utilisant ES6:

const arr1test = arr1.slice().sort()
const arr2test = arr2.slice().sort()
const equal = !arr1test.some((val, idx) => val !== arr2test[idx])

Crée des copies superficielles de chaque tableau et les trie. Puis utilise some()pour parcourir les arr1testvaleurs, en vérifiant chaque valeur par rapport à la valeur dans arr2testavec le même index. Si toutes les valeurs sont égales, les some()rendements false, et à son tour equalevalue à true.

Pourrait également utiliser every(), mais il faudrait parcourir chaque élément du tableau pour satisfaire untrue résultat, alors qu'il some()sera libéré dès qu'il trouve une valeur qui n'est pas égale:

const equal = arr1test.every((val, idx) => val === arr2test[idx])

2

J'avais des valeurs entières simples dans un projet de jeu
Avait moins de valeurs dans chaque tableau, aussi, avait besoin de ce tableau d'origine intact
, j'avais donc fait ce qui suit, cela a bien fonctionné. (Code modifié pour coller ici)

var sourceArray = [1, 2, 3];
var targetArray = [3, 2, 1];

if (sourceArray.length !== targetArray.length) {
    // not equal
    // did something
    return false;
}

var newSortedSourceArray = sourceArray.slice().sort();
var newSortedTargetArray = targetArray.slice().sort();

if (newSortedSourceArray.toString() !== newSortedTargetArray.toString()) { // MAIN CHECK
    // not equal
    // did something
    return false;
}
else {
    // equal
    // did something
    // continued further below
}

// did some more work

return true;

J'espère que cela pourra aider.


2

Utilisation d'ES6

Nous utiliserons la equalsfonction de Ramda , mais à la place, nous pouvons utiliser celle de Lodash ou Underscore isEqual:

const R = require('ramda');

const arraysHaveSameValues = (arr1, arr2) => R.equals( [...arr1].sort(), [...arr2].sort() )

En utilisant l'opportateur de diffusion, nous évitons de muter les tableaux d'origine et nous gardons notre fonction pure.


2

Vous pouvez utiliser à la reduceplace des boucles pour paraître intelligent, mais au risque de voir vos collègues développeurs vous considérer comme un âne intelligent.

function isArrayContentSame(a, b) {
  if (Array.isArray(a) && Array.isArray(b) && a.length == b.length) {
    a = a.concat().sort()
    b = b.concat().sort()
    return a.reduce((acc,e,i) => acc && e === b[i], true)
  } else {
    return false;
  }
}

1

Si les éléments du tableau sont des primitives (nombres ou caractères uniques), vous pouvez utiliser une combinaison de comparaison de longueurs et d'ensembles.

function equalArrayItems(arr1, arr2) {
  if (arr1.length !== arr2.length) return false
  const set1 = new Set(arr1)
  const set2 = new Set(arr2)
  const set3 = new Set(arr1, arr2)
  return set1.size === set3.size && set2.size === set3.size
}

1

Nous sommes déjà en 2020 mais j'ai remarqué que la plupart des autres solutions utilisent le tri, O (n * log n), utilisent des bibliothèques ou ont une complexité O (n ^ 2).

Voici une solution Javascript pure de complexité linéaire, O (n):

/**
 * Check if two arrays of strings or numbers have the same values regardless of the order
 * @param {string[]|number[]} arr1
 * @param {string[]|number[]} arr2
 * @return {boolean}
 */    
compareArrays = (arr1, arr2) => {
    if (arr1.length !== arr2.length) return false;
    const lk1 = {};
    const lk2 = {};
    let i = arr1.length;
    while (--i >= 0) {
        lk1[arr1[i]] = true;
        lk2[arr2[i]] = true
    }
    i = arr1.length;
    while (--i >= 0) {
        const v = arr1[i];
        if (lk1[v] !== lk2[v]) return false;
    }
    return true
}

Tests:

compareArrays([2, 4], [4, 2]) => true
compareArrays([2, 4], [4, 2, 7]) => false
compareArrays([], []) => true

1
Hé, c'est une super entrée! C'est assez compliqué, mais cela a du sens. J'ai une question: je ne suis pas très familier avec la notation Big O, mais cet algorithme est sûrement O (2n)? Mais ne pensez pas que cela fasse une grande différence.
Carlos Precioso

1
@CarlosPrecioso C'est correct et O (2n) = O (n). La complexité ne change pas en multipliant par un facteur constant
SC1000

0

Si vous utilisez Prototype Framework, vous pouvez utiliser la méthode intersect d'un tableau pour découvrir qu'ils sont identiques (quel que soit l'ordre):

var array1 = [1,2];
var array2 = [2,1];

if(array1.intersect(array2).length === array1.length) {
    alert("arrays are the same!");
}

Cela ne fonctionne pas - [1,2].intersect([1,2,3]).length === [1,2].lengthrenvoie vrai. Vous devriez également comparer la longueur des tableaux d'origine, j'ai édité l'article pour le démontrer.
GMA

En fait, je viens de réaliser que ma modification suggérée ne fonctionne pas dans le cas de doublons ... par exemple, elle retournera false pour array1 = [1,1,2]; array2 = [1,1,2];... la réponse d'origine n'échoue pas pour cette entrée.
GMA

Vous pouvez faire le contraire avec_.difference(array1, array2).length;
Vic

0

veuillez vérifier cette réponse

var arr1= [12,18];
var arr2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];
for(i=0;i<arr1.length;i++)
{
var array1=arr1[i];
for(j=0;j<arr2.length;j++)
{
    var array2=arr2[j];
    if(array1==array2)
    {
return true;
    }
}
}

2
Ceci est fonctionnellement équivalent à cette réponse , sauf pour quelques erreurs. Tout d'abord, tout cela doit être enveloppé dans une fonction, sinon le returnsera sans effet. Deuxièmement, vous devez vérifier les tableaux triés, car [1,2]et [2,1]seront détectés comme étant différents. Troisièmement et le plus important, cela ne vérifiera en fait que si un élément est le même. Le conditionnel devrait être if (array1!==array2) {return false;}. Peut-être que cela peut vous aider à l'avenir!
Carlos Precioso

1
Et comme commentaire supplémentaire, essayez d'utiliser l'indentation pour une meilleure compréhension du flux de code, ainsi que des noms de variables plus clairs. Par exemple: array1et array2pourrait être renommé elem1et elem2. Ces deux conseils vous éviteront bien des maux de tête à l'avenir!
Carlos Precioso

2
Après un examen plus approfondi, pourquoi la double boucle? Les deux tableaux doivent avoir la même longueur, sinon ils ne sont pas directement égaux. De cette façon, vous ne pouvez utiliser qu'une seule boucle. À l'heure actuelle, ce code vérifie si l' un des éléments du premier tableau se trouve n'importe où dans le second. Cochez cette réponse pour voir comment vous devez l'implémenter. Bonne chance dans votre aventure JavaScript!
Carlos Precioso

0

Répondre après longtemps, mais j'espère que cela aidera quelqu'un qui recherche une solution simple et des débutants modernes.

Nous pouvons maintenant y parvenir en utilisant plusieurs bibliothèques comme lodash,underscore , etc. (Ceux - ci devient une partie du projet de nos jours , en raison de la simplicité, de multiples fonctionnalités et une utilisation élevée)

Vous pouvez utiliser l'intersection de la bibliothèque lodash.

_.intersection(['2-1', '1'], ['2-2', '3-1', '2-1']); 
// => ['2-1']

Cela fonctionnera pour tout type de données.


0

Si vous voulez comparer deux tableaux et vérifier si un objet est le même dans les deux tableaux, cela fonctionnera. Exemple :

Array1 = [a, b, c, d]
Array2 = [d, e, f, g]

Ici, «d» est commun dans les deux tableaux, donc cette fonction retournera la valeur vraie.

  cehckArray(array1, array2) {
    for (let i = 0; i < array1.length; i++) {
      for (let j = 0; j < array2.length; j++) {
        if (array1[i] === array2[j]) {
          return true;
        }
      }
    }
    // Return if no common element exist 
    return false;
  }

0

Essaye ça

function arraysEqual(arr1, arr2){
    if (!Array.isArray(arr1) || !Array.isArray(arr2) || arr1.length!=arr2.length)
        return false;

    return arr1.length==arr1.filter(word => arr2.includes(word)).length;
}

0

J'ai un autre moyen basé sur la réponse acceptée.

function compareArrays(array1, array2) {

    if (
        !Array.isArray(array1)
        || !Array.isArray(array2)
        || array1.length !== array2.length
    ) return false;

    var first = array1.sort().map(value => (String(value))).join();
    var second = array2.sort().map(value => (String(value))).join();

    return first == second ? true : false;
}

Hé, bienvenue dans StackOverflow! Bien que cette réponse fonctionne dans certains cas, il y aurait des cas spécifiques où ce ne serait pas le cas. Tout d'abord, gardez à l'esprit que .sort () modifie le tableau d'origine. De nos jours, c'est considéré comme une mauvaise hygiène, c'est pourquoi la réponse originale fait d'abord un .concat (), pour en faire une copie.
Carlos Precioso

Et deuxième point, cela ne fonctionnerait pas de manière cohérente avec le reste de JavaScript. {foo: "bar"} === {foo: "bar"} renvoie false (ce sont deux objets distincts créés séparément); donc compareArrays ([{foo: "bar"}], [{foo: "bar"}]), devrait également retourner false pour la cohérence. Cependant, avec votre implémentation, elle renvoie true, car la représentation sous forme de chaîne des objets est la même. Cela peut être un comportement souhaité, ou non, mais dont il faut être conscient dans tous les cas.
Carlos Precioso

0

Une fonction pour comparer deux tableaux, pour vérifier si les deux ont les mêmes éléments. Même s'ils sont en panne ...

C'est bon pour les tableaux simples. [String, Number, Boolean, null, NaN].

Je n'utilise pas .sort (), cela modifie le tableau d'origine. Certains disent que c'est mauvais ...

Mise en garde. Cette fonction est limitée, elle ne peut pas comparer les objets "[], {}" ou les fonctions de ces tableaux, les tableaux sont des objets.

   let arraysHasSameElements = (arr1, arr2) => {
        let count =
            // returns counting of occurrences.
            (arr, val) => arr.reduce((count, curr) => (curr === val ? 1 : 0) + count, 0);

        /* this will return true if lengths of the arrays is equal.
           then compare them.*/
        return arr1.length === arr2.length

            // compare arr1 against arr2.
            && arr1.reduce((checks, val) =>

                /*  creating array of checking if a value has equal amount of occurrences
                    in both arrays, then adds true 'check'. */
                checks.concat(count(arr1, val) === count(arr2, val)), [])

                // checking if each check is equal to true, then .every() returns true.
                .every(check => check);
    }

    let arr1 = ['',-99,true,NaN,21,null,false,'help',-99,'help',NaN], 
        arr2 = [null,-99,'',NaN,NaN,false,true,-99,'help',21,'help'];
    arraysHasSameElements(arr1, arr2); //true

    let arr3 = [false,false,false,false,false,false], 
        arr4 = [false,false,false,false,false,false]
    arraysHasSameElements(arr3, arr4); //true


    // here we have uncommented version.
    let arraysHasSameElements = (arr1, arr2) => {
        let count = (arr, val) => arr.reduce((count, curr) => (curr === val ? 1:0) + count, 0);
        return arr1.length === arr2.length && arr1.reduce((checks, val) =>
            checks.concat(count(arr1, val) === count(arr2, val)), []).every(check => check);
    }

-1

Solution simple pour comparer les deux tableaux:

var array1 = [2, 4];
var array2 = [4, 2];

array1.sort();
array2.sort();

if (array1[0] == array2[0]) {
    console.log("Success");
}else{
    console.log("Wrong");
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.