Ich möchte zwei Arrays vergleichen ... idealerweise effizient. Nichts Besonderes, nur true
wenn sie identisch sind und false
wenn 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?
javascript
arrays
json
Julian H. Lam
quelle
quelle
([] == []) == false
.Antworten:
Um Arrays zu vergleichen, durchlaufen Sie sie und vergleichen Sie jeden Wert:
Arrays vergleichen:
Verwendungszweck:
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:
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:
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:Ich habe ein kleines Testwerkzeug für beide Funktionen erstellt .
Bonus: Verschachtelte Arrays mit
indexOf
undcontains
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/
quelle
this[i] !== array[i]
statt!=
.equals
statt aufgerufen werdencompare
. Zumindest in .NET gibt compare normalerweise ein vorzeichenbehaftetes int zurück, das angibt, welches Objekt größer als das andere ist. Siehe: Comparer.Compare .Dies funktioniert zwar nur für skalare Arrays (siehe Hinweis unten), ist jedoch kurz:
Rr, in ECMAScript 6 / CoffeeScript / TypeScript mit Pfeilfunktionen:
(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:
Z.B:
Dann würde der obige Code geben
true
quelle
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];
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:
quelle
_.isEqual([1,2,3], [2,1,3]) => false
isEqual
Funktionalität wollen, können Sie immer das lodash.isequal Modul verwenden_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
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:
Dabei werden die Objekte
a1
unda2
in 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.
quelle
Es ist unklar, was Sie unter "identisch" verstehen. Sind beispielsweise die Arrays
a
undb
darunter identisch (beachten Sie die verschachtelten Arrays)?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ürdefalse
. Es funktioniert im allgemeinen Fall, was JSON- undjoin()
-basierte Lösungen nicht können:quelle
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.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
arrayCompare
Prozedur, die sich nur mit dem Durchlaufen der Arrays befasst. Von dort aus bauen wir unsere anderen grundlegenden Vergleichsfunktionen wiearrayEqual
undarrayDeepEqual
usw.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 Vergleichsfunktionf
und zwei Eingabearraysxs
undys
. Zum größten Teil rufen wir nurf (x) (y)
jedes Element in den Eingabearrays auf. Wir geben frühzeitig zurück,false
wenn das benutzerdefinierte Ergebnisf
zurückkehrtfalse
- 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
arrayCompare
können wir mit unserer Funktion leicht andere Funktionen erstellen, die wir möglicherweise benötigen. Wir werden mit der Grundschule beginnenarrayEqual
...So einfach ist das.
arrayEqual
kann mitarrayCompare
und einer Komparatorfunktion definiert werden, diea
mit derb
Verwendung verglichen wird===
(für strikte Gleichheit).Beachten Sie, dass wir auch
equal
als eigene Funktion definieren. Dies unterstreicht die RollearrayCompare
einer Funktion höherer Ordnung bei der Verwendung unseres Komparators erster Ordnung im Kontext eines anderen Datentyps (Arrays).Loser Vergleich
Wir könnten genauso einfach
arrayLooseEqual
mit einem definieren==
. Wenn Sie nun1
(Number) mit'1'
(String) vergleichen, ist das Ergebnistrue
…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
arrayCompare
Verfahren ist vielseitig genug, um es so anzuwenden, dass ein tiefer Gleichstellungstest zum Kinderspiel wird…So einfach ist das. Wir bauen einen tiefen Komparator mit einer anderen Funktion höherer Ordnung. Dieses Mal werden wir
arrayCompare
mit einem benutzerdefinierten Komparator verpackt , der prüft, oba
undb
sind Arrays. Wenn ja, wenden SiearrayDeepCompare
anderweitig den Vergleicha
undb
den 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 mitequal
,looseEqual
oder jede andere Komparator wir machen.Da
arrayDeepCompare
es sich um Curry handelt, können wir es teilweise anwenden, wie wir es auch in den vorherigen Beispielen getan habenFü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
id
Wert hat ...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.
Beliebiger Vergleich (Beispiel)
Oder was wäre, wenn Sie einen völlig willkürlichen Vergleich anstellen wollten? Vielleicht möchte ich wissen, ob jeder
x
größer ist als jedery
...Weniger ist mehr
Sie sehen, wir machen tatsächlich mehr mit weniger Code. Es ist nichts Kompliziertes an
arrayCompare
sich 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 einenRegExp
Komparator 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
arrayEqual
in 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.quelle
arrayCompare
? Ja, die Funktion ist Curry, aber sie unterscheidet sich vonsome
undevery
.arrayCompare
nimmt 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 (zarrayEqual
. 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 ^ _ ^Im Geiste der ursprünglichen Frage:
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
alle (69%) von user2782196
Reduzierung (74%) durch DEIs
join & toString (78%) von Gaizka Allende & vivek
halb toString (90%) von Victor Palomo
stringify (100%) von radtek
quelle
Array.from({length: 1000}).map((a,v)=>
$ {v}.padStart(10,2));
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.
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:
Ich habe auch eine kurze jsfiddle mit der Funktion und diesem Beispiel geschrieben:
http://jsfiddle.net/Roundaround/DLkxX/
quelle
Obwohl dies viele Antworten hat, eine, von der ich glaube, dass sie hilfreich ist:
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:
Du wirst kriegen
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:
Du wirst kriegen
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.
quelle
In den gleichen Zeilen wie JSON.encode wird join () verwendet.
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.
Wenn die Reihenfolge gleich bleiben soll, da es sich nur um eine Schleife handelt, ist keine Sortierung erforderlich.
quelle
.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.checkArrays([1,2,3] , ["1,2",3]) == true
und es ist sehr unwahrscheinlich, dass dies der Fall ist!join()
so verwenden macht es subtil fehlerhaft!Hier ist eine Typescript-Version:
Einige Testfälle für Mokka:
quelle
Wenn Sie ein Testframework wie Mocha mit der Chai- Assertionsbibliothek verwenden, können Sie Arrays mit Deep Equality vergleichen.
Dies sollte nur dann true zurückgeben, wenn die Arrays an entsprechenden Indizes gleiche Elemente aufweisen.
quelle
Wenn es sich nur um zwei Arrays von Zahlen oder Zeichenfolgen handelt, ist dies eine schnelle einzeilige
quelle
[11]
. Ziemlich offensichtlich, warum dies passiert und wie es behoben werden kann.In meinem Fall enthalten verglichene Arrays nur Zahlen und Zeichenfolgen. Diese Funktion zeigt Ihnen, ob Arrays dieselben Elemente enthalten.
Lass es uns testen!
quelle
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.are_arrs_equal([1,2], [2,1])
kehrttrue
wie erwartet zurück. Vielleicht ist diese Lösung nicht ideal, aber sie hat bei mir funktioniert.are_arrs_match([1,2], ["1,2"])
(Rückgabetrue
). Beachten Sie auch, dass derthe sort()
Aufruf die Eingabearrays ändert - dies ist möglicherweise nicht wünschenswert.Dies vergleicht 2 unsortierte Arrays:
quelle
Versuchen Sie für eine Reihe von Zahlen:
Code-Snippet anzeigen
Hinweis: Diese Methode funktioniert nicht, wenn das Array auch Zeichenfolgen enthält, z
a2 = [1, "2,3"]
.quelle
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.quelle
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).
quelle
Herer ist meine Lösung:
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.
quelle
equal({}, {a:1})
undequal({}, null)
und diese Fehler aus:equal({a:2}, null)
So habe ich es gemacht.
quelle
Vergleichen von 2 Arrays:
Funktion aufrufen
quelle
Ich glaube an schlicht
JS
und mitECMAScript 2015
, was süß und einfach zu verstehen ist.hoffe es wird jemandem helfen.
quelle
Erweiterung der Idee von Tomáš Zato. Tomas 'Array.prototype.compare sollte den Namen Array.prototype.compareIdentical haben.
Es geht weiter:
Aber scheitert am:
Hier ist eine bessere (meiner Meinung nach) Version:
http://jsfiddle.net/igos/bcfCY/
quelle
////// ODER ///////
quelle
Ein anderer Ansatz mit sehr wenig Code (mit Array Reduce und Array Includes ):
Wenn Sie auch die Gleichheit der Ordnung vergleichen wollen:
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
.quelle
Ein einfacher Ansatz:
quelle
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
quelle
Rekursiv & arbeitet an NESTED- Arrays:
quelle
Arbeiten mit MEHREREN Argumenten mit VERSCHACHTELTE Arrays:
quelle
quelle