Gibt es eine Möglichkeit, den Unterschied zwischen zwei Arrays in JavaScript zurückzugeben?
Zum Beispiel:
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
// need ["c", "d"]
javascript
arrays
array-difference
John Adawan
quelle
quelle
O(a1.length x log(a2.length))
- ist diese Leistung in JavaScript möglich?Antworten:
Ich gehe davon aus, dass Sie ein normales Array vergleichen. Wenn nicht, müssen Sie die for- Schleife in eine for .. in- Schleife ändern .
Eine bessere Lösung ist die Verwendung von Filtern, wenn Sie sich nicht für die Abwärtskompatibilität interessieren. Trotzdem funktioniert diese Lösung.
quelle
var a1 = ['a', 'b'];
undvar a2 = ['a', 'b', 'c', 'd', 'b'];
, wird es falsche Antwort zurückgeben , dh['c', 'd', 'b']
statt['c', 'd']
.function diff2(a, b) { var i, la = a.length, lb = b.length, res = []; if (!la) return b; else if (!lb) return a; for (i = 0; i < la; i++) { if (b.indexOf(a[i]) === -1) res.push(a[i]); } for (i = 0; i < lb; i++) { if (a.indexOf(b[i]) === -1) res.push(b[i]); } return res; }
Es gibt einen besseren Weg mit ES7:
Überschneidung
Denn
[1,2,3] [2,3]
es wird nachgeben[2,3]
. Auf der anderen Seite wird for[1,2,3] [2,3,5]
das Gleiche zurückgeben.Unterschied
Denn
[1,2,3] [2,3]
es wird nachgeben[1]
. Auf der anderen Seite wird for[1,2,3] [2,3,5]
das Gleiche zurückgeben.Für einen symmetrischen Unterschied können Sie Folgendes tun:
Auf diese Weise erhalten Sie ein Array, das alle Elemente von arr1 enthält, die nicht in arr2 enthalten sind, und umgekehrt
Wie @Joshaven Potter in seiner Antwort betonte, können Sie dies zu Array.prototype hinzufügen, damit es wie folgt verwendet werden kann:
quelle
< 0
anstatt== -1
Array
Differenz wird als so genannte bezeichnetset operation
, da die Suche nach Eigenschaften die eigene Aufgabe vonSet
s ist, die um Größenordnungen schneller sind alsindexOf
/includes
. Einfach ausgedrückt ist Ihre Lösung sehr ineffizient und ziemlich langsam.Set
, Werte müssen eindeutig sein, nein?[1,2,3] [2,3,5]
, die Zahlen sind eindeutig, aber wenn Sie gesagt[1,1,2,3] [1,2,3,5]
und erwartet hätten[1]
, könnten Sie nicht verwendenSet
. Ihre Lösung würde aber auch nicht funktionieren: - / Am Ende habe ich diese Funktion erstellt, weil ich keinen zufriedenstellenden Weg gefunden habe, dies prägnanter zu machen. Wenn Sie Ideen dazu haben, würde ich gerne wissen!Array.includes()
ES7 nicht Funktion statt ES6? (1) (2) - und um fortzufahren, könnten Sie mit ES6Array.some()
zBlet intersection = aArray.filter(a => bArray.some(b => a === b))
nein verwenden?Code-Snippet anzeigen
Hinweis indexOf und Filter sind in dh vor ie9 nicht verfügbar.
quelle
[1,2,3].diff([3,4,5])
folgt verwenden : Sie wird zurückgegeben,[1,2]
anstatt[1,2,4,5]
das Problem in der ursprünglichen Frage nicht zu lösen. Beachten Sie dies.Dies ist bei weitem der einfachste Weg, mit jQuery genau das gewünschte Ergebnis zu erzielen:
diff
jetzt enthält was drin war wasold_array
nicht drin istnew_array
quelle
{a: 1} != {a: 1}
) ( Beweis ).not
mit einem Array verwendet jQuery das integrierte Dienstprogramm,.grep()
das speziell zum Filtern von Arrays vorgesehen ist. Ich kann nicht sehen, dass sich das ändert.Die Differenzmethode in Unterstrich (oder deren Drop-In-Ersatz, Lo-Dash ) kann dies auch:
Wie bei jeder Unterstreichungsfunktion können Sie sie auch in einem objektorientierteren Stil verwenden:
quelle
Einfaches JavaScript
Es gibt zwei mögliche Interpretationen für "Unterschied". Ich lasse Sie wählen, welche Sie wollen. Angenommen, Sie haben:
Wenn Sie erhalten möchten
['a']
, verwenden Sie diese Funktion:Wenn Sie erhalten möchten
['a', 'c']
(alle Elemente, die in einema1
odera2
, aber nicht in beiden enthalten sind - die sogenannte symmetrische Differenz ), verwenden Sie diese Funktion:Lodash / Unterstrich
Wenn Sie lodash verwenden, können Sie
_.difference(a1, a2)
(Fall 1 oben) oder_.xor(a1, a2)
(Fall 2) verwenden.Wenn Sie Underscore.js verwenden, können Sie die
_.difference(a1, a2)
Funktion für Fall 1 verwenden.ES6-Set für sehr große Arrays
Der obige Code funktioniert in allen Browsern. Bei großen Arrays mit mehr als 10.000 Elementen wird es jedoch ziemlich langsam, da es eine O (n²) -Komplexität aufweist. In vielen modernen Browsern können wir das ES6-
Set
Objekt nutzen, um die Dinge zu beschleunigen. Lodash wird automatisch verwendet,Set
wenn es verfügbar ist. Wenn Sie lodash nicht verwenden, verwenden Sie die folgende Implementierung, die vom Blog-Beitrag von Axel Rauschmayer inspiriert wurde :Anmerkungen
Das Verhalten für alle Beispiele kann überraschend oder nicht offensichtlich sein, wenn Sie sich für -0, +0, NaN oder spärliche Arrays interessieren . (Für die meisten Anwendungen spielt dies keine Rolle.)
quelle
Um den symmetrischen Unterschied zu erhalten , müssen Sie die Arrays auf beide Arten vergleichen (oder auf alle Arten bei mehreren Arrays).
ES7 (ECMAScript 2016)
ES6 (ECMAScript 2015)
ES5 (ECMAScript 5.1)
Beispiel:
Unterschied zwischen Arrays von Objekten
Beispiel:
quelle
Ein sauberer Ansatz in ES6 ist die folgende Lösung.
Unterschied
Überschneidung
Disjunktive Union (symmetrischer Unterschied)
quelle
a1 = ['a', 'b', 'e']
: e wird nicht extrahiert.In diesem Fall können Sie ein Set verwenden . Es ist für diese Art von Operation (Vereinigung, Schnittmenge, Differenz) optimiert.
Stellen Sie sicher, dass dies für Ihren Fall gilt, sobald keine Duplikate mehr zulässig sind.
quelle
Set
Funktion herunterladen können, ohne alles andere bekommen zu müssen ...Wenn Sie beide Arrays zusammenführen, werden eindeutige Werte nur einmal angezeigt, sodass indexOf () mit lastIndexOf () identisch ist.
quelle
Um ein Array von einem anderen zu subtrahieren, verwenden Sie einfach das folgende Snippet:
Es werden ['1,' 2 ',' 6 '] zurückgegeben, die Elemente des ersten Arrays sind, die im zweiten nicht vorhanden sind.
Entsprechend Ihrem Problembeispiel ist daher der folgende Code die genaue Lösung:
quelle
Mit der Ankunft von ES6 mit Sets und Splat-Operator (zum Zeitpunkt der Arbeit nur in Firefox, überprüfen Sie die Kompatibilitätstabelle ) können Sie den folgenden Liner schreiben:
was dazu führen wird
[ "c", "d" ]
.quelle
b.filter(x => !a.indexOf(x)))
O(n + m)
Ihre Lösung,O(n * m)
bei der n und m die Länge von Arrays sind. Nehmen Sie lange Listen und meine Lösung wird in Sekunden ausgeführt, während Ihre Stunden dauern wird.a.filter(x => !b1.has(x))
ist einfacher. Und beachten Sie die Spezifikation nur die Komplexität erfordert zu seinn * f(m) + m
mitf(m)
sublinear im Durchschnitt. Es ist besser alsn * m
, aber nicht unbedingtn + m
.var difference = [...new Set([...a].filter(x => !b1.has(x)))];
Warum erstellen Sie ein doppeltes ' a' -Array? Warum verwandeln Sie das Ergebnis des Filters in eine Menge und dann wieder in ein Array? Ist das nicht gleichbedeutend mitvar difference = a.filter(x => !b1.has(x));
Funktionsansatz mit ES2015
Das Berechnen der
difference
zwischen zwei Arrays ist eine derSet
Operationen. Der Begriff gibt bereits an, dass der nativeSet
Typ verwendet werden sollte, um die Suchgeschwindigkeit zu erhöhen. Auf jeden Fall gibt es drei Permutationen, wenn Sie die Differenz zwischen zwei Mengen berechnen:Hier ist eine funktionale Lösung, die diese Permutationen widerspiegelt.
Links
difference
:Richtig
difference
:differencer
ist trivial. Es ist nurdifferencel
mit umgedrehten Argumenten. Sie können der Einfachheit halber eine Funktion schreiben :const differencer = flip(differencel)
. Das ist alles!Symmetrisch
difference
:Jetzt, da wir die linke und die rechte haben, wird die Implementierung der Symmetrie ebenfalls
difference
trivial:Ich denke, dieses Beispiel ist ein guter Ausgangspunkt, um einen Eindruck davon zu bekommen, was funktionale Programmierung bedeutet:
Programmieren mit Bausteinen, die auf viele verschiedene Arten miteinander verbunden werden können.
quelle
Eine Lösung mit
indexOf()
ist für kleine Arrays in Ordnung, aber mit zunehmender Länge nähert sich die Leistung des Algorithmus anO(n^2)
. Hier ist eine Lösung, die bei sehr großen Arrays eine bessere Leistung erzielt, indem Objekte als assoziative Arrays zum Speichern der Array-Einträge als Schlüssel verwendet werden. Es werden auch doppelte Einträge automatisch entfernt, es funktioniert jedoch nur mit Zeichenfolgenwerten (oder Werten, die sicher als Zeichenfolgen gespeichert werden können):quelle
Die obige Antwort von Joshaven Potter ist großartig. Es werden jedoch Elemente in Array B zurückgegeben, die sich nicht in Array C befinden, aber nicht umgekehrt. Wenn
var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
dann zum Beispiel Folgendes ausgegeben wird: ==>[1,2,6]
, aber nicht[1,2,6,7]
, was der tatsächliche Unterschied zwischen den beiden ist. Sie können weiterhin den obigen Potter-Code verwenden, aber den Vergleich auch einmal rückwärts wiederholen:Dies sollte Folgendes ausgeben:
[ 1, 2, 6, 7 ]
quelle
Ein anderer Weg, um das Problem zu lösen
Sie können auch die Pfeilfunktionssyntax verwenden:
quelle
quelle
difference
in einer zukünftigen Version als Funktion eingeführt wird und diese Funktion eine andere Funktionssignatur als Ihre hat, wird Ihr Code oder fremde Bibliotheken, die diese Funktion verwenden, beschädigt.Sehr einfache Lösung mit der Filterfunktion von JavaScript:
quelle
Wie wäre es damit:
Auf diese Weise können Sie also
array1.diff(array2)
den Unterschied ermitteln (schreckliche Zeitkomplexität für den Algorithmus - O (array1.length x array2.length), glaube ich).quelle
Mit http://phrogz.net/JS/ArraySetMath.js können Sie:
quelle
Das funktioniert bei mir
quelle
filter
)fn
Rückrufparameter, mit dem Sie angeben können, wie Array-Elemente verglichen werden sollenquelle
length
Werte zwischenzuspeichern. Es ist bereits einfaches Eigentum. jsperf.com/array-length-cachingDies funktioniert: Führen Sie die beiden Arrays zusammen, suchen Sie nach den Duplikaten und verschieben Sie das, was nicht dupliziert wurde, in ein neues Array, das den Unterschied ausmacht.
quelle
// es6 Ansatz
quelle
Symmetrische und lineare Komplexität . Benötigt ES6.
quelle
Noch eine Antwort, aber anscheinend hat niemand jsperf erwähnt, wo sie verschiedene Algorithmen und technologische Unterstützung vergleichen: https://jsperf.com/array-difference-javascript scheint die Verwendung von Filtern die besten Ergebnisse zu erzielen . Vielen Dank
quelle
Ich denke nur ... für eine Herausforderung ;-) würde dies funktionieren ... (für grundlegende Arrays von Strings, Zahlen usw.) keine verschachtelten Arrays
Beachten Sie, dass die Sortierung wahrscheinlich nicht wie oben angegeben sein wird. Rufen Sie jedoch bei Bedarf .sort () im Array auf, um sie zu sortieren.
quelle
Ich wollte eine ähnliche Funktion, die ein altes Array und ein neues Array aufnimmt und mir ein Array von hinzugefügten Elementen und ein Array von entfernten Elementen gibt, und ich wollte, dass es effizient ist (also keine .contains!).
Sie können mit meiner vorgeschlagenen Lösung hier spielen: http://jsbin.com/osewu3/12 .
Kann jemand irgendwelche Probleme / Verbesserungen an diesem Algorithmus sehen? Vielen Dank!
Codeauflistung:
quelle
Ich suchte nach einer einfachen Antwort, bei der keine unterschiedlichen Bibliotheken verwendet wurden, und fand eine eigene, die meiner Meinung nach hier nicht erwähnt wurde. Ich weiß nicht, wie effizient es ist oder so, aber es funktioniert;
Für meinen Code müssen auch Duplikate herausgenommen werden, aber ich denke, das wird nicht immer bevorzugt.
Ich denke, der Hauptnachteil ist, dass möglicherweise viele Optionen verglichen werden, die bereits abgelehnt wurden.
quelle
Littlebit Fix für die beste Antwort
Dies berücksichtigt den aktuellen Elementtyp. b / c Wenn wir a [a1 [i]] machen, konvertiert es einen Wert von seinem ursprünglichen Wert in einen String, sodass wir den tatsächlichen Wert verloren haben.
quelle