Wie vergleiche ich Arrays in JavaScript?

988

Ich möchte zwei Arrays vergleichen ... idealerweise effizient. Nichts Besonderes, nur truewenn sie identisch sind und falsewenn nicht. Es überrascht nicht, dass der Vergleichsoperator nicht zu funktionieren scheint.

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-Codierung für jedes Array funktioniert, aber gibt es eine schnellere oder "bessere" Möglichkeit, Arrays einfach zu vergleichen, ohne jeden Wert durchlaufen zu müssen?

Julian H. Lam
quelle
5
Sie könnten zuerst ihre Länge vergleichen und wenn sie gleich sind, jeden Wert.
TJHeuvel
55
Was macht zwei Arrays für Sie gleich? Gleiche Elemente? Gleiche Reihenfolge der Elemente? Die Codierung als JSON funktioniert nur, solange das Element des Arrays in JSON serialisiert werden kann. Wenn das Array Objekte enthalten kann, wie tief würden Sie gehen? Wann sind zwei Objekte "gleich"?
Felix Kling
48
@FelixKling, die Definition von "Gleichheit" ist definitiv ein subtiles Thema, aber für Leute, die aus höheren Sprachen zu JavaScript kommen, gibt es keine Entschuldigung für Albernheit wie ([] == []) == false.
Alex D
4
@AlexD Es sieht so aus, als würden Arrays Referenzgleichheit verwenden, was Sie erwarten würden. Es wäre ziemlich schrecklich, wenn Sie das nicht könnten
JonnyRaa
3
@AlexD Ich kann mir keine Sprache vorstellen, in der dies nicht passiert. In C ++ würden Sie zwei Zeiger vergleichen - false. In Java machen Sie dasselbe wie in Javascript. In PHP durchläuft etwas hinter den Kulissen die Arrays - nennen Sie PHP eine höhere Sprache?
Tomáš Zato - Wiedereinsetzung Monica

Antworten:

877

Um Arrays zu vergleichen, durchlaufen Sie sie und vergleichen Sie jeden Wert:

Arrays vergleichen:

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

Verwendungszweck:

[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;

Sie können sagen " Aber es ist viel schneller, Strings zu vergleichen - keine Schleifen ... " Nun, dann sollten Sie beachten, dass es ARE-Schleifen gibt. Erste rekursive Schleife, die Array in String konvertiert, und zweite, die zwei Strings vergleicht. Diese Methode ist also schneller als die Verwendung von Zeichenfolgen .

Ich glaube, dass größere Datenmengen immer in Arrays gespeichert werden sollten, nicht in Objekten. Wenn Sie jedoch Objekte verwenden, können diese auch teilweise verglichen werden.
Hier ist wie:

Objekte vergleichen:

Ich habe bereits erwähnt, dass zwei Objektinstanzen werden nie gleich sein, auch wenn sie dieselben Daten zur Zeit enthalten:

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

Dies hat einen Grund, da es beispielsweise private Variablen innerhalb von Objekten geben kann.

Wenn Sie jedoch nur die Objektstruktur verwenden, um Daten zu enthalten, ist ein Vergleich weiterhin möglich:

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

Denken Sie jedoch daran, dass dies dazu dient, JSON-ähnliche Daten zu vergleichen, nicht Klasseninstanzen und andere Dinge. Wenn Sie mehr komplizierte Objekte vergleichen möchten, schauen Sie sich diese Antwort und ihre überlange Funktion an .
Damit dies funktioniert Array.equals, müssen Sie die ursprüngliche Funktion ein wenig bearbeiten:

...
    // 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]) {
...

Ich habe ein kleines Testwerkzeug für beide Funktionen erstellt .

Bonus: Verschachtelte Arrays mit indexOfundcontains

Samy Bencherif hat nützliche Funktionen für den Fall vorbereitet , dass Sie in verschachtelten Arrays nach einem bestimmten Objekt suchen. Diese finden Sie hier: https://jsfiddle.net/SamyBencherif/8352y6yw/

Tomáš Zato - Monica wieder einsetzen
quelle
27
Wenn Sie strenge Vergleiche durchführen möchten, verwenden Sie this[i] !== array[i]statt !=.
Tim S.
38
Ihre Methode sollte equalsstatt aufgerufen werden compare. Zumindest in .NET gibt compare normalerweise ein vorzeichenbehaftetes int zurück, das angibt, welches Objekt größer als das andere ist. Siehe: Comparer.Compare .
Oliver
15
Dies ist nicht nur der richtige Weg, sondern auch wesentlich effizienter. Hier ist ein kurzes jsperf-Skript, das ich für alle in dieser Frage vorgeschlagenen Methoden vorbereitet habe. jsperf.com/comparing-arrays2
Tolga E
96
Das Ändern des Prototyps eines eingebauten Typs ist definitiv nicht der richtige Weg
Jasper
31
Außerdem geht es nicht darum, ob das Umschreiben einfach ist, sondern darum, dass eine Antwort nichts empfehlen sollte, was als schlechte Praxis angesehen wird ( developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/… ) und sollte Tun Sie dies definitiv nicht unter der Überschrift "Der richtige Weg"
Jasper
386

Dies funktioniert zwar nur für skalare Arrays (siehe Hinweis unten), ist jedoch kurz:

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

Rr, in ECMAScript 6 / CoffeeScript / TypeScript mit Pfeilfunktionen:

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

(Hinweis: 'Skalar' bedeutet hier Werte, die direkt mit verglichen werden können ===. Also: Zahlen, Zeichenfolgen, Objekte als Referenz, Funktionen als Referenz. Weitere Informationen zu den Vergleichsoperatoren finden Sie in der MDN-Referenz .)

AKTUALISIEREN

Nach dem, was ich aus den Kommentaren gelesen habe, kann das Sortieren des Arrays und Vergleichen ein genaues Ergebnis liefern:

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

Z.B:

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

Dann würde der obige Code geben true

user2782196
quelle
19
Ich mag das, obwohl die Leser wissen sollten, dass dies nur bei sortierten Arrays funktioniert.
Ellen Spertus
13
Es funktioniert auf jeder Art von Arrays, sortiert oder nicht @espertus
Michał Miszczyszyn
36
Ja genau. Diese Funktion soll zwei Arrays vergleichen. Es spielt keine Rolle, ob sie sortiert sind oder nicht. Ihre aufeinander folgenden Elemente müssen gleich sein.
Michał Miszczyszyn
22
@espertus In der Tat wird true nicht zurückgegeben, wenn die Elemente in beiden Arrays nicht genau dieselbe Reihenfolge haben. Das Ziel einer Gleichheitsprüfung besteht jedoch nicht darin, zu prüfen, ob sie dieselben Elemente enthalten, sondern zu prüfen, ob sie dasselbe Element in derselben Reihenfolge haben.
Quentin Roy
7
Wenn Sie überprüfen möchten, ob beide Arrays gleich sind und dieselben unsortierten Elemente enthalten (aber nicht mehrfach verwendet werden), können Sie a1.length==a2.length && a1.every((v,i)=>a2.includes(v))var a1 =[1,2,3], a2 = [3,2,1];var a1 =[1,3,3], a2 = [1,1,3];
Folgendes
208

Ich verwende die Underscore-Bibliothek gerne für Array- / Objekt-Codierungsprojekte ... in Underscore und Lodash sieht es einfach so aus, wenn Sie Arrays oder Objekte vergleichen:

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean
Jason Boerner
quelle
22
Beachten Sie, dass die Reihenfolge wichtig ist _.isEqual([1,2,3], [2,1,3]) => false
Vitaliy Alekask
3
oder wenn Sie nur die isEqualFunktionalität wollen, können Sie immer das lodash.isequal Modul verwenden
hellatan
6
Sie können vielleicht _.difference () verwenden; Wenn Ihnen die Bestellung egal ist
Ronan Quillevere
5
Wir können das Array vor dieser Prüfung sortieren, wenn die Reihenfolge keine Rolle spielt_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Filype
prägnanteste und direkteste Antwort IMHO :-)
Kieran Ryan
121

Dies ist meiner Meinung nach der einfachste Weg, dies mit JSON stringify zu tun, und in einigen Situationen kann es die beste Lösung sein:

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

Dabei werden die Objekte a1und a2in Strings , damit sie verglichen werden können. Die Reihenfolge ist in den meisten Fällen wichtig, da dies das Objekt mithilfe eines Sortieralgorithmus sortieren kann, der in einer der obigen Antworten gezeigt wird.

Bitte beachten Sie, dass Sie nicht mehr das Objekt, sondern die Zeichenfolgendarstellung des Objekts vergleichen. Es kann nicht genau das sein, was Sie wollen.

radtek
quelle
gute Antwort, aber warum [] == [] false zurückgeben? beide sind einfache Objekte, warum dann?
Pardeep Jain
4
@PardeepJain, dies liegt daran, dass der Gleichheitsoperator in ECMAScript for Objects standardmäßig true zurückgibt, wenn sie auf denselben Speicherort verweisen. Versuchen Sie var x = y = []; // Jetzt gibt Gleichheit true zurück.
Radtek
7
Nur um zu beachten, dass die JSON-Stringify-Funktion nicht schnell ist. Die Verwendung mit größeren Arrays führt definitiv zu Verzögerungen.
Lukas Liesis
6
In der Frage wird speziell gefragt, ob es einen besseren / schnelleren Weg als die Verwendung von JSON.stringify gibt.
Don Hatch
Es wird detaillierter erläutert, warum dies in bestimmten Situationen eine gute Lösung sein kann.
Radtek
61

Es ist unklar, was Sie unter "identisch" verstehen. Sind beispielsweise die Arrays aund bdarunter identisch (beachten Sie die verschachtelten Arrays)?

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

Hier ist eine optimierte Array-Vergleichsfunktion, die die entsprechenden Elemente jedes Arrays nacheinander unter strikter Gleichheit vergleicht und keinen rekursiven Vergleich von Array-Elementen durchführt, die selbst Arrays sind, was bedeutet, dass für das obige Beispiel zurückgegeben werden arraysIdentical(a, b)würde false. Es funktioniert im allgemeinen Fall, was JSON- und join()-basierte Lösungen nicht können:

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;
};
Tim Down
quelle
@ASDF: Aus der Frage, was "identisch" bedeutet, geht nicht hervor. Offensichtlich führt diese Antwort nur eine flache Überprüfung durch. Ich werde eine Notiz hinzufügen.
Tim Down
dies schlägt für arraysIdentical fehl ([1, 2, [3, 2]], [1, 2, [3, 2]]);
Gopinath Shiva
4
@ GopinathShiva: Nun, es schlägt nur fehl, wenn Sie erwarten, dass es zurückkehrt true. Die Antwort erklärt, dass dies nicht der Fall ist. Wenn Sie verschachtelte Arrays vergleichen müssen, können Sie leicht eine rekursive Prüfung hinzufügen.
Tim Down
59

Der praktische Weg

Ich denke, es ist falsch zu sagen, dass eine bestimmte Implementierung "The Right Way ™" ist, wenn sie im Gegensatz zu einer "falschen" Lösung nur "richtig" ("richtig") ist. Die Lösung von Tomáš ist eine deutliche Verbesserung gegenüber dem String-basierten Array-Vergleich, aber das bedeutet nicht, dass sie objektiv "richtig" ist. Was ist überhaupt richtig ? Ist es das schnellste? Ist es das flexibelste? Ist es am einfachsten zu verstehen? Ist es das schnellste Debugging? Verwendet es die wenigsten Operationen? Hat es irgendwelche Nebenwirkungen? Keine Lösung kann das Beste von allem haben.

Tomáš könnte sagen, dass seine Lösung schnell ist, aber ich würde auch sagen, dass sie unnötig kompliziert ist. Es wird versucht, eine All-in-One-Lösung zu sein, die für alle Arrays funktioniert, ob verschachtelt oder nicht. Tatsächlich akzeptiert es sogar mehr als nur Arrays als Eingabe und versucht immer noch, eine "gültige" Antwort zu geben.


Generika bieten Wiederverwendbarkeit

Meine Antwort wird das Problem anders angehen. Ich beginne mit einer generischen arrayCompareProzedur, die sich nur mit dem Durchlaufen der Arrays befasst. Von dort aus bauen wir unsere anderen grundlegenden Vergleichsfunktionen wie arrayEqualund arrayDeepEqualusw.

// arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayCompare = f => ([x,...xs]) => ([y,...ys]) =>
  x === undefined && y === undefined
    ? true
    : Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys)

Meiner Meinung nach benötigt die beste Art von Code nicht einmal Kommentare, und dies ist keine Ausnahme. Hier passiert so wenig, dass Sie das Verhalten dieses Verfahrens fast mühelos verstehen können. Sicher, einige der ES6-Syntax scheinen Ihnen jetzt fremd zu sein, aber das liegt nur daran, dass ES6 relativ neu ist.

Wie der Typ andeutet, arrayCompareübernimmt die Vergleichsfunktion fund zwei Eingabearrays xsund ys. Zum größten Teil rufen wir nur f (x) (y)jedes Element in den Eingabearrays auf. Wir geben frühzeitig zurück, falsewenn das benutzerdefinierte Ergebnis fzurückkehrt false- dank der &&Kurzschlussbewertung. Ja, dies bedeutet, dass der Komparator die Iteration vorzeitig stoppen und verhindern kann, dass der Rest des Eingabearrays durchlaufen wird, wenn dies nicht erforderlich ist.


Strenger Vergleich

Als nächstes arrayComparekönnen wir mit unserer Funktion leicht andere Funktionen erstellen, die wir möglicherweise benötigen. Wir werden mit der Grundschule beginnen arrayEqual...

// equal :: a -> a -> Bool
const equal = x => y =>
  x === y // notice: triple equal

// arrayEqual :: [a] -> [a] -> Bool
const arrayEqual =
  arrayCompare (equal)

const xs = [1,2,3]
const ys = [1,2,3]
console.log (arrayEqual (xs) (ys))      //=> true
// (1 === 1) && (2 === 2) && (3 === 3)  //=> true

const zs = ['1','2','3']
console.log (arrayEqual (xs) (zs))      //=> false
// (1 === '1')                          //=> false

So einfach ist das. arrayEqualkann mit arrayCompareund einer Komparatorfunktion definiert werden, die amit der bVerwendung verglichen wird ===(für strikte Gleichheit).

Beachten Sie, dass wir auch equalals eigene Funktion definieren. Dies unterstreicht die Rolle arrayCompareeiner Funktion höherer Ordnung bei der Verwendung unseres Komparators erster Ordnung im Kontext eines anderen Datentyps (Arrays).


Loser Vergleich

Wir könnten genauso einfach arrayLooseEqualmit einem definieren ==. Wenn Sie nun 1(Number) mit '1'(String) vergleichen, ist das Ergebnis true

// looseEqual :: a -> a -> Bool
const looseEqual = x => y =>
  x == y // notice: double equal

// arrayLooseEqual :: [a] -> [a] -> Bool
const arrayLooseEqual =
  arrayCompare (looseEqual)

const xs = [1,2,3]
const ys = ['1','2','3']
console.log (arrayLooseEqual (xs) (ys))    //=> true
// (1 == '1') && (2 == '2') && (3 == '3')  //=> true

Tiefer Vergleich (rekursiv)

Sie haben wahrscheinlich bemerkt, dass dies nur ein flacher Vergleich ist. Sicherlich ist Tomášs Lösung "The Right Way ™", weil sie einen tiefen Vergleich impliziert, oder?

Nun, unser arrayCompareVerfahren ist vielseitig genug, um es so anzuwenden, dass ein tiefer Gleichstellungstest zum Kinderspiel wird…

// isArray :: a -> Bool
const isArray =
  Array.isArray

// arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayDeepCompare = f =>
  arrayCompare (a => b =>
    isArray (a) && isArray (b)
      ? arrayDeepCompare (f) (a) (b)
      : f (a) (b))

const xs = [1,[2,[3]]]
const ys = [1,[2,['3']]]
console.log (arrayDeepCompare (equal) (xs) (ys)) //=> false
// (1 === 1) && (2 === 2) && (3 === '3')         //=> false

console.log (arrayDeepCompare (looseEqual) (xs) (ys)) //=> true
// (1 == 1) && (2 == 2) && (3 == '3')                 //=> true

So einfach ist das. Wir bauen einen tiefen Komparator mit einer anderen Funktion höherer Ordnung. Dieses Mal werden wir arrayComparemit einem benutzerdefinierten Komparator verpackt , der prüft, ob aund bsind Arrays. Wenn ja, wenden Sie arrayDeepCompareanderweitig den Vergleich aund bden benutzerdefinierten Komparator ( f) an. Dies ermöglicht es uns, das tiefe Vergleichsverhalten von dem tatsächlichen Vergleich der einzelnen Elemente zu trennen. Das heißt, wie das Beispiel zeigt, können wir tief vergleichen mit equal, looseEqualoder jede andere Komparator wir machen.

Da arrayDeepComparees sich um Curry handelt, können wir es teilweise anwenden, wie wir es auch in den vorherigen Beispielen getan haben

// arrayDeepEqual :: [a] -> [a] -> Bool
const arrayDeepEqual =
  arrayDeepCompare (equal)

// arrayDeepLooseEqual :: [a] -> [a] -> Bool
const arrayDeepLooseEqual =
  arrayDeepCompare (looseEqual)

Für mich ist dies bereits eine deutliche Verbesserung gegenüber Tomášs Lösung, da ich je nach Bedarf explizit einen flachen oder tiefen Vergleich für meine Arrays auswählen kann .


Objektvergleich (Beispiel)

Was ist nun, wenn Sie eine Reihe von Objekten oder etwas haben? Vielleicht möchten Sie diese Arrays als "gleich" betrachten, wenn jedes Objekt den gleichen idWert hat ...

// idEqual :: {id: Number} -> {id: Number} -> Bool
const idEqual = x => y =>
  x.id !== undefined && x.id === y.id

// arrayIdEqual :: [a] -> [a] -> Bool
const arrayIdEqual =
  arrayCompare (idEqual)

const xs = [{id:1}, {id:2}]
const ys = [{id:1}, {id:2}]
console.log (arrayIdEqual (xs) (ys)) //=> true
// (1 === 1) && (2 === 2)            //=> true

const zs = [{id:1}, {id:6}]
console.log (arrayIdEqual (xs) (zs)) //=> false
// (1 === 1) && (2 === 6)            //=> false

So einfach ist das. Hier habe ich Vanilla JS-Objekte verwendet, aber dieser Komparatortyp kann für jeden Objekttyp verwendet werden. sogar Ihre benutzerdefinierten Objekte. Die Lösung von Tomáš müsste komplett überarbeitet werden, um diese Art von Gleichstellungstest zu unterstützen

Deep Array mit Objekten? Kein Problem. Wir haben vielseitige, generische Funktionen entwickelt, damit sie in einer Vielzahl von Anwendungsfällen funktionieren.

const xs = [{id:1}, [{id:2}]]
const ys = [{id:1}, [{id:2}]]
console.log (arrayCompare (idEqual) (xs) (ys))     //=> false
console.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true

Beliebiger Vergleich (Beispiel)

Oder was wäre, wenn Sie einen völlig willkürlichen Vergleich anstellen wollten? Vielleicht möchte ich wissen, ob jeder xgrößer ist als jeder y...

// gt :: Number -> Number -> Bool
const gt = x => y =>
  x > y

// arrayGt :: [a] -> [a] -> Bool
const arrayGt = arrayCompare (gt)

const xs = [5,10,20]
const ys = [2,4,8]
console.log (arrayGt (xs) (ys))     //=> true
// (5 > 2) && (10 > 4) && (20 > 8)  //=> true

const zs = [6,12,24]
console.log (arrayGt (xs) (zs))     //=> false
// (5 > 6)                          //=> false

Weniger ist mehr

Sie sehen, wir machen tatsächlich mehr mit weniger Code. Es ist nichts Kompliziertes an arrayComparesich und jeder der von uns erstellten benutzerdefinierten Komparatoren hat eine sehr einfache Implementierung.

Mit Leichtigkeit können wir genau definieren , wie wir wollen für zwei Arrays verglichen werden - flach, tief, streng, lose, einige Objekteigenschaft oder eine willkürliche Berechnung oder eine beliebige Kombination davon - alle eine Prozedur , arrayCompare. Vielleicht sogar einen RegExpKomparator ausdenken! Ich weiß, wie Kinder diese Regexps lieben ...

Ist es das schnellste? Nee. Aber es muss wahrscheinlich auch nicht sein. Wenn Geschwindigkeit die einzige Metrik ist, die zur Messung der Qualität unseres Codes verwendet wird, wird eine Menge wirklich großartiger Code weggeworfen. Deshalb nenne ich diesen Ansatz den praktischen Weg . Oder vielleicht um fairer zu sein, ein praktischer Weg. Diese Beschreibung ist für diese Antwort geeignet, da ich nicht sage, dass diese Antwort nur im Vergleich zu einer anderen Antwort praktisch ist. es ist objektiv wahr. Wir haben ein hohes Maß an Praktikabilität mit sehr wenig Code erreicht, über den man sehr leicht nachdenken kann. Kein anderer Code kann sagen, dass wir diese Beschreibung nicht verdient haben.

Ist es damit die "richtige" Lösung für Sie? Das liegt an Ihnen zu entscheiden. Und niemand sonst kann das für Sie tun; Nur Sie wissen, was Ihre Bedürfnisse sind. In fast allen Fällen schätze ich einfachen, praktischen und vielseitigen Code gegenüber cleverer und schneller Art. Was Sie schätzen, kann unterschiedlich sein. Wählen Sie also aus, was für Sie funktioniert.


Bearbeiten

Meine alte Antwort konzentrierte sich mehr auf die Zerlegung arrayEqualin winzige Prozeduren. Es ist eine interessante Übung, aber nicht wirklich der beste (praktischste) Weg, um dieses Problem anzugehen. Wenn Sie interessiert sind, können Sie diesen Revisionsverlauf sehen.

Vielen Dank
quelle
8
"Die beste Art von Code braucht nicht einmal Kommentare" ... ich hasse es, es zu sagen, aber dieser Code könnte eher einen Kommentar und / oder einen anderen Namen verwenden - "Vergleichen" ist ziemlich vage. Wenn ich richtig lese, ist Ihr "Vergleichen" im Wesentlichen ein rekursives "jeder". Ich glaube. Oder ist es ein Curry rekursives "einige"? Hmm. Dies erfordert mehr Nachdenken als nötig. Vielleicht wäre ein besserer Name "arraysEquivalent", wobei die Standardterminologie der "Äquivalenzbeziehung" verwendet wird. Oder noch klarer (für mich jedenfalls) "rekursiv äquivalent".
Don Hatch
1
@ DonHatch danke für die Gelegenheit zu antworten. Mit "vergleichen" meinst du arrayCompare? Ja, die Funktion ist Curry, aber sie unterscheidet sich von someund every. arrayComparenimmt einen Komparator und zwei Arrays zum Vergleichen. Ich habe einen speziell generischen Namen gewählt, weil wir Arrays mit jeder beliebigen Funktion vergleichen können. Die Funktion ist Curry, so dass sie darauf spezialisiert werden kann, neue Array-Vergleichsfunktionen zu erstellen (z arrayEqual. B. ). Können Sie einen besseren Namen vorschlagen? In welchen Bereichen benötigen Sie Ihrer Meinung nach zusätzliche Kommentare oder Erklärungen? Ich freue mich zu diskutieren ^ _ ^
Danke
1
Ich bin mir nicht sicher, ob mein Punkt noch klar ist - aber mein Punkt ist, dass Ihre Funktion nicht wirklich dazu gedacht ist, eine beliebige Funktion zu übernehmen , glaube ich nicht -, dass sie eine Äquivalenzbeziehung annehmen soll und eine Äquivalenzbeziehung zurückgibt. Das ist wichtig - es würde nichts Sinnvolles bewirken (glaube ich nicht), wenn eine andere Art von willkürlicher Binärfunktion wie die von mir erwähnten gegeben würde, selbst solche, die die Leute oft als "Vergleichen" bezeichnen. Daher halte ich es für hilfreich, anstelle von "Vergleichen" "Äquivalent" in den Namen zu setzen.
Don Hatch
1
@ftor, Autor: super hilfreiche Antwort, gute Arbeit, +1. Feedback: Sie befürworten Einfachheit, aber für viele Entwickler ist ein Ausdruck mit drei Pfeilen in einer Zeile auf keinen Fall einfach oder leicht zu verstehen. Zum Beispiel: f => ([x, ... xs]) => ([y, ... ys]) =>. Ich benutze dies ständig und musste es immer noch mental zerlegen, anstatt es nur anzusehen. Der zweite Punkt ist richtig, verwenden Sie jeden. Selbst wenn Sie Ihre Gründe abwägen, erscheint es mir insgesamt nicht nur besser, sondern auch aus Ihrer Sicht, wenn Sie versuchen, auf Ihre Designphilosophie zu schließen.
Whitneyland
1
Ich verstehe, dass dies ein Ort zum Lernen ist, aber ich gehe hier davon aus, dass der durchschnittliche Programmierer, der den funktionalen Stil studiert, jede Curry-Funktion in eine nicht-Curry-Funktion umwandeln kann. Meine Antwort macht nicht den Vorschlag, dass dieser Stil in Ihrem eigenen Programm verwendet werden soll - schreiben Sie ihn ohne Eile, schreiben Sie ihn mit Ihren eigenen Einrückungsregeln, schreiben Sie ihn, wie Sie wollen - ich schreibe meine Antworten in einem Stil, von dem ich glaube, dass er das ausdrückt Programm am besten. Ich möchte auch andere einladen, die Art und Weise herauszufordern, wie wir unsere Programme syntaktisch ausdrücken
Vielen Dank,
54

Im Geiste der ursprünglichen Frage:

Ich möchte zwei Arrays vergleichen ... idealerweise effizient . Nichts Besonderes , nur wahr, wenn sie identisch sind, und falsch, wenn nicht.

Ich habe Leistungstests für einige der hier vorgeschlagenen einfacheren Vorschläge mit den folgenden Ergebnissen (schnell bis langsam) durchgeführt:

während (67%) von Tim Down

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

alle (69%) von user2782196

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

Reduzierung (74%) durch DEIs

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

join & toString (78%) von Gaizka Allende & vivek

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

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

halb toString (90%) von Victor Palomo

a1 == a2.toString();

stringify (100%) von radtek

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

In den folgenden Beispielen wird davon ausgegangen, dass es sich bei den Arrays um sortierte eindimensionale Arrays handelt. .lengthDer Vergleich wurde für einen gemeinsamen Benchmark entfernt (fügen Sie a1.length === a2.lengtheinen der Vorschläge hinzu und Sie erhalten eine Leistungssteigerung von ~ 10%). Wählen Sie die für Sie am besten geeigneten Lösungen aus und kennen Sie die Geschwindigkeit und die jeweiligen Einschränkungen.

Hinweis ohne Bezug: Es ist interessant zu sehen, wie die Leute alle auslöserfreudigen John Waynes auf den Abstimmungsknopf bekommen, um absolut legitime Antworten auf diese Frage zu erhalten.

unitario
quelle
Der Link öffnet einen leeren Test.
Alexander Abakumov
Wenn Sie die Arraygröße erhöhen, gelten diese Zahlen nicht (insbesondere der Ansatz zum Reduzieren). Versuchen Sie es mit Array.from({length: 1000}).map((a,v)=> $ {v}.padStart(10,2));
Narayon
es funktioniert nur für flache Array
Ramesh Rajendran
28

Aufbauend auf Tomáš Zatos Antwort stimme ich zu, dass es am schnellsten ist, nur durch die Arrays zu iterieren. Zusätzlich sollte (wie andere bereits angegeben haben) die Funktion gleich / gleich heißen, nicht vergleichen. Vor diesem Hintergrund habe ich die Funktion geändert, um das Vergleichen von Arrays auf Ähnlichkeit - dh sie haben dieselben Elemente, aber nicht in der richtigen Reihenfolge - für den persönlichen Gebrauch zu handhaben, und dachte, ich würde sie hier für alle sichtbar machen.

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

Diese Funktion verwendet einen zusätzlichen Parameter von strict, der standardmäßig true ist. Dieser strenge Parameter definiert, ob die Arrays in beiden Inhalten und in der Reihenfolge dieser Inhalte vollständig gleich sein müssen oder einfach nur denselben Inhalt enthalten müssen.

Beispiel:

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

Ich habe auch eine kurze jsfiddle mit der Funktion und diesem Beispiel geschrieben:
http://jsfiddle.net/Roundaround/DLkxX/

Evan Steinkerchner
quelle
12

Obwohl dies viele Antworten hat, eine, von der ich glaube, dass sie hilfreich ist:

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

In der Frage, wie die Struktur des Arrays aussehen wird, wird nicht angegeben. Wenn Sie also sicher sind, dass Sie keine verschachtelten Arrays oder Objekte in Ihrem Array haben (mir ist es passiert, bin ich darauf gekommen Antwort) Der obige Code wird funktionieren.

Was passiert ist, dass wir den Spread-Operator (...) verwenden, um beide Arrays zu verknüpfen, und dann Set verwenden, um alle Duplikate zu entfernen. Sobald Sie das haben, können Sie ihre Größen vergleichen. Wenn alle drei Arrays die gleiche Größe haben, können Sie loslegen.

Diese Antwort ignoriert auch die Reihenfolge der Elemente , wie ich sagte, die genaue Situation ist mir passiert, so dass vielleicht jemand in der gleichen Situation hier landen könnte (wie ich).


Edit1.

Beantwortung der Frage von Dmitry Grinko: "Warum haben Sie hier den Spread-Operator (...) verwendet - ... neues Set? Es funktioniert nicht."

Betrachten Sie diesen Code:

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

Du wirst kriegen

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

Um mit diesem Wert arbeiten zu können, müssen Sie einige Set-Eigenschaften verwenden (siehe https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ). Auf der anderen Seite, wenn Sie diesen Code verwenden:

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

Du wirst kriegen

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

Das ist der Unterschied, der erstere würde mir ein Set geben, es würde auch funktionieren, da ich die Größe dieses Sets bekommen könnte, aber der letztere gibt mir das Array, das ich brauche, was direkter zur Auflösung ist.

Jeferson Euclides
quelle
Warum haben Sie hier den Spread-Operator (...) verwendet - ... neues Set? Es funktioniert nicht.
Dmitry Grinko
Dmitry Grinko Ich glaube, ich habe Ihre Frage auf meinem Edit1 beantwortet. Aber ich bin mir nicht sicher, was Sie damit gemeint haben, dass es nicht funktioniert, da beide Antworten Sie in die Quere kommen können
Jeferson Euclides
10

In den gleichen Zeilen wie JSON.encode wird join () verwendet.

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

Das einzige Problem ist, wenn Sie sich für Typen interessieren, die beim letzten Vergleich getestet wurden. Wenn Sie sich für Typen interessieren, müssen Sie eine Schleife ausführen.

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

Wenn die Reihenfolge gleich bleiben soll, da es sich nur um eine Schleife handelt, ist keine Sortierung erforderlich.

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
Epascarello
quelle
3
Dies funktioniert nur für bestimmte Arrays und ist bei großen Arrays sehr langsam.
Tomáš Zato - Wiedereinsetzung Monica
2
Das Generieren von JSON ist ebenfalls eine Schleife. Sie wissen einfach (oder es scheint so) nichts davon. Neben dem Schleifen erfordert das Generieren von JSON auch mehr Speicher - es werden vor dem Vergleich zwei Zeichenfolgendarstellungen der Arrays erstellt. Die Downwote-Funktion ist implementiert, um Antworten vom Besten zum Schlechtesten zu ordnen. Ich denke, Ihre Antwort ist keine gute Antwort, deshalb habe ich sie abgelehnt.
Tomáš Zato - Wiedereinsetzung Monica
2
Entschuldigung, ich habe gerade JSON statt gesagt .join(). Vielleicht würde ich Sie nicht so beurteilen, wenn Sie Ihre zweite Lösung als primär bezeichnen würden (da es die bessere ist, obwohl sie gegen mehrdimensionale Arrays zahnlos ist). Bisher habe ich alle Antworten, die Arrays in Strings konvertieren, herabgestuft. Außerdem habe ich alle, die den richtigen Weg verwenden, positiv bewertet, falls Sie dies benötigen, um es zu wissen. Dies bedeutet die Antwort von @Tim Down und die von Bireys.
Tomáš Zato - Wiedereinsetzung Monica
6
Erste Version FEHLT: checkArrays([1,2,3] , ["1,2",3]) == trueund es ist sehr unwahrscheinlich, dass dies der Fall ist!
Doin
2
@epascarello: Ja, das können Sie, aber (abgesehen von der Ineffizienz des von Ihnen vorgeschlagenen sehr langen Trennzeichens) bedeutet dies, dass es Randfälle gibt (in denen das Array zufällig einen String mit Ihrem Trennzeichen enthält), in denen sich die Funktion checkArrays () schlecht verhält . Dies ist möglicherweise kein Problem, wenn Sie etwas über den Inhalt der Arrays wissen (Sie können also ein Trennzeichen auswählen, von dem Sie sicher sind, dass es nicht in den Array-Elementen enthalten ist), aber wenn Sie versuchen, einen allgemeinen Array-Vergleich zu schreiben Funktion, dann mit join()so verwenden macht es subtil fehlerhaft!
Doin
7

Hier ist eine Typescript-Version:

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

Einige Testfälle für Mokka:

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)
})
Esqarrouth
quelle
6

Wenn Sie ein Testframework wie Mocha mit der Chai- Assertionsbibliothek verwenden, können Sie Arrays mit Deep Equality vergleichen.

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

Dies sollte nur dann true zurückgeben, wenn die Arrays an entsprechenden Indizes gleiche Elemente aufweisen.

Metakermit
quelle
6

Wenn es sich nur um zwei Arrays von Zahlen oder Zeichenfolgen handelt, ist dies eine schnelle einzeilige

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
Gaizka Allende
quelle
const array1 = [1]; const array2 = [1, 1]; console.log (array1.join ('') === array2.join ('')) // gibt true zurück
Dan M.
es sollte nicht: array1.join ('') ist '1' und array2.join ('') ist '11'
Gaizka Allende
Entschuldigung, Tippfehler. Das erste Array sollte sein [11]. Ziemlich offensichtlich, warum dies passiert und wie es behoben werden kann.
Dan M.
Ich bin mir nicht sicher, worum es dir geht, es ist ziemlich einfach: [1] .join () ist "1" und [1,1] .join () ist "1,1", also werden sie niemals gleich sein
Gaizka Allende
Bitte lesen Sie meinen Kommentar noch einmal genauer durch. Wenn Sie es immer noch nicht sehen, plündern Sie bitte unter ideone.com/KFu427
Dan M.
5

In meinem Fall enthalten verglichene Arrays nur Zahlen und Zeichenfolgen. Diese Funktion zeigt Ihnen, ob Arrays dieselben Elemente enthalten.

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

Lass es uns testen!

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
yesnik
quelle
Die Frage fordert Sie nicht zum Sortieren auf, daher ist Ihre Lösung für Beispiele wie falsch are_arrs_equal([1,2], [2,1]). In anderen Diskussionen auf dieser Seite erfahren Sie auch, warum das Stringifizieren unnötig, fragil und falsch ist.
Behandle deine Mods gut
are_arrs_equal([1,2], [2,1])kehrt truewie erwartet zurück. Vielleicht ist diese Lösung nicht ideal, aber sie hat bei mir funktioniert.
Yesnik
Das ist genau das Problem, diese beiden sind für eine geordnete Datenstruktur in keinem vernünftigen Sinne des Wortes "gleich" gleich . Es sind Arrays, keine Sets, und wenn Sie Set-Gleichheit wollen, sollten Sie es so nennen - und eine andere Frage beantworten. :-)
deine Mods gut
1
Ich stimme den obigen Kommentaren zu, aber diese Lösung funktioniert auch für mich in meinen einfachen Arrays von ganzen Zahlen, bei denen die Reihenfolge nicht wichtig ist, also werde ich sie verwenden.
Tomazahlin
1
Fehlgeschlagen für are_arrs_match([1,2], ["1,2"])(Rückgabe true). Beachten Sie auch, dass der the sort()Aufruf die Eingabearrays ändert - dies ist möglicherweise nicht wünschenswert.
versuchen-fangen-endlich
5

Dies vergleicht 2 unsortierte Arrays:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}
Nathan Boolean Trujillo
quelle
Obwohl teuer (in Bezug auf Rechenressourcen), ist dies eine robuste Lösung, die für verschiedene Typen geeignet sein sollte und nicht auf Sortierung angewiesen ist!
user3.1415927
5

Versuchen Sie für eine Reihe von Zahlen:

a1==''+a2

Hinweis: Diese Methode funktioniert nicht, wenn das Array auch Zeichenfolgen enthält, z a2 = [1, "2,3"].

Kamil Kiełczewski
quelle
kluger Trick ..
Javadba
4

Wir könnten dies auf funktionale Weise tun, indem wir every( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every ) verwenden.

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
Peonikel
quelle
4

Ihr Code wird den Fall nicht angemessen behandeln, wenn beide Arrays dieselben Elemente, jedoch nicht in derselben Reihenfolge haben.

Schauen Sie sich meinen Code mit Ihrem Beispiel an, das zwei Arrays vergleicht, deren Elemente Zahlen sind. Sie können ihn für andere Elementtypen ändern oder erweitern (indem Sie .join () anstelle von .toString () verwenden).

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

Durga Patra
quelle
3

Herer ist meine Lösung:

/**
 * 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;
};

Funktioniert mit jeder verschachtelten Datenstruktur und ignoriert offensichtlich die Methoden von Objekten. Denken Sie nicht einmal daran, Object.prototype mit dieser Methode zu erweitern. Als ich dies einmal versuchte, war jQuery kaputt;)

Bei den meisten Arrays ist es immer noch schneller als bei den meisten Serialisierungslösungen. Dies ist wahrscheinlich die schnellste Vergleichsmethode für Arrays von Objektdatensätzen.

Harry
quelle
nicht gut! diese geben wahr: equal({}, {a:1})und equal({}, null)und diese Fehler aus:equal({a:2}, null)
kristianlm
3
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

So habe ich es gemacht.

Leed
quelle
Gute Lösung - aber ich frage mich in bestimmten Situationen, ob es nicht immer wie beabsichtigt funktioniert, z. B. bei bestimmten Grundelementen oder tief verschachtelten Arrays? Ich hoffe, es funktioniert unter allen Umständen
Ben Rondeau
3

Vergleichen von 2 Arrays:

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

Funktion aufrufen

var isBool = compare(arr1.sort().join(),arr2.sort().join());
Amay Kulkarni
quelle
Diese Antwort funktioniert nicht, da sich das === für Arrays nicht wie erwartet verhält.
Michael Yang
Die Antwort funktioniert, obwohl === hier keine Bedeutung hat (da sort () nur für Arrays funktioniert). Auch == wird auch funktionieren.
Amay Kulkarni
Probieren Sie es selbst aus; Wenn Sie diesen Code ausführen, wird false ausgegeben. Dies liegt am Vergleich der Referenzwerte der Arrays mit == und === anstelle ihrer tatsächlichen Werte. == und === sind nur für den primitiven Typvergleich vorgesehen.
Michael Yang
Es gibt true zurück, wir haben es verwendet, aber ich habe '===' jetzt entfernt, da es nicht notwendig ist
Amay Kulkarni
Ah, ich habe nicht bemerkt, dass Sie in eine Zeichenfolge konvertieren und die Funktion nach dem Sortieren und Verbinden aufrufen. meine Entschuldigungen.
Michael Yang
3

Ich glaube an schlicht JSund mit ECMAScript 2015, was süß und einfach zu verstehen ist.

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

}

hoffe es wird jemandem helfen.

ArifMustafa
quelle
1
Warum ist die Überprüfung umgekehrt erforderlich? Wir wissen, dass die Arrays dieselbe Größe haben. Wenn also jedes Element in Array1 auch in Array2 gefunden wird; Warum sollten wir dann überprüfen müssen, ob jedes Element in Array2 auch in Array1 enthalten ist?
JeffryHouser
2

Erweiterung der Idee von Tomáš Zato. Tomas 'Array.prototype.compare sollte den Namen Array.prototype.compareIdentical haben.

Es geht weiter:

[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;

Aber scheitert am:

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

Hier ist eine bessere (meiner Meinung nach) Version:

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/

Igor S.
quelle
2
-1. Wenn es in dem von Ihnen angegebenen Beispiel "fehlschlägt", ist dies nur bei einer etwas willkürlichen Definition von "fehlgeschlagen" der Fall. Warum würden Sie erwarten, dass diese beiden unterschiedlichen Arrays als gleich angesehen werden? Sie haben noch nicht einmal erklärt, welches Konzept der Gleichheit Sie hier implementieren möchten oder warum es sinnvoll oder hilfreich ist, aber es sieht so aus, als ob Sie möchten, dass mehrdimensionale Arrays verglichen werden, als wären sie auf eindimensional reduziert Einsen. Wenn ja, haben Sie das nicht einmal erreicht: [1,2] .compare ([[1,2]]) gibt bei Ihrer Version falsch aus, genau wie bei Tomáš.
Mark Amery
Basierend auf dem, was ich schließen könnte, sagt er, dass [1, 2, 3, 4] und [1, 3, 2, 4] als gleich verglichen werden sollten (Reihenfolge spielt keine Rolle).
Gautham Badhrinathan
2
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);

////// ODER ///////

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)
Vasanth
quelle
Sie können auch eine Funktion
ausführen,
2

Ein anderer Ansatz mit sehr wenig Code (mit Array Reduce und Array Includes ):

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

Wenn Sie auch die Gleichheit der Ordnung vergleichen wollen:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • Die lengthÜberprüfung stellt sicher, dass die Menge der Elemente in einem Array nicht nur eine Teilmenge der anderen ist.

  • Der Reduzierer wird verwendet, um durch ein Array zu gehen und nach jedem Element in einem anderen Array zu suchen. Wenn ein Element nicht gefunden wird, wird die Reduzierungsfunktion zurückgegeben false.

    1. Im ersten Beispiel wird getestet, ob ein Element enthalten ist
    2. Das zweite Beispiel prüft auch die Bestellung
DEls
quelle
1
Könnten Sie Ihren Code ein wenig erklären, um diese Antwort klarer zu machen?
8.
1. Vergleichen Sie die Array-Längen, um sicherzustellen, dass ein Array keine Teilmenge des anderen ist
DEls
2. Verwenden Sie den Reduzierer, um durch ein Array zu gehen und nach jedem Element in einem anderen Array zu suchen. Wenn ein Element nicht gefunden wird, gibt die Reduzierungsfunktion 'false' zurück
DEls
@DEls: Bearbeiten Sie Ihre Erklärung in der Antwort (leicht umformuliert und erweitert). Sie können jetzt Ihre Kommentare entfernen und den ersten und diesen Kommentar als veraltet markieren.
versuchen-fangen-endlich
2

Ein einfacher Ansatz:

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;
}
Pedro Rodrigues
quelle
2

Bereits einige gute Antworten. Aber ich möchte eine andere Idee teilen, die sich beim Vergleich von Arrays als zuverlässig erwiesen hat. Wir können zwei Arrays mit JSON.stringify () vergleichen . Es wird eine Zeichenfolge aus dem Array erstellt und somit zwei erhaltene Zeichenfolgen aus zwei Arrays auf Gleichheit verglichen

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
AL-Zami
quelle
2

Rekursiv & arbeitet an NESTED- Arrays:

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"]]]
));;  
JMI MADISON
quelle
2

Arbeiten mit MEHREREN Argumenten mit VERSCHACHTELTE Arrays:

//: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"   ]]],
));; 
JMI MADISON
quelle
2
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  
Pedro Bustamante
quelle