Was ist der einfachste, bibliotheksfreie Code zum Implementieren von Array-Schnittpunkten in Javascript? Ich möchte schreiben
intersection([1,2,3], [2,3,4,5])
und bekomme
[2, 3]
Was ist der einfachste, bibliotheksfreie Code zum Implementieren von Array-Schnittpunkten in Javascript? Ich möchte schreiben
intersection([1,2,3], [2,3,4,5])
und bekomme
[2, 3]
break
zuSimple js loops
erhöht die ops / s ~ 10MAntworten:
Verwenden Sie eine Kombination aus
Array.prototype.filter
undArray.prototype.indexOf
:Oder wie vrugtehagel in den Kommentaren vorgeschlagen hat, können Sie den neueren
Array.prototype.includes
für noch einfacheren Code verwenden:Für ältere Browser:
quelle
intersection([1,2,1,1,3], [1])
kehrt zurück[1, 1, 1]
. Sollte es nicht einfach zurückkehren[1]
?array2.indexOf(n) != -1
kann man aucharray2.includes(n)
für noch einfacheren Code schreiben .Destruktiv scheint am einfachsten zu sein, besonders wenn wir davon ausgehen können, dass die Eingabe sortiert ist:
Zerstörungsfrei muss ein Haar komplizierter sein, da wir Indizes verfolgen müssen:
quelle
intersect_safe
:length
ist eine Eigenschaft in Arrays, keine Methode. Es gibt eine nicht freigegebene Variablei
inresult.push(a[i]);
. Schließlich funktioniert dies im allgemeinen Fall einfach nicht: Zwei Objekte, bei denen laut>
Operator keines größer als das andere ist, sind nicht unbedingt gleich.intersect_safe( [ {} ], [ {} ] )
Beispielsweise wird (sobald die zuvor genannten Fehler behoben sind) ein Array mit einem Element angegeben, was eindeutig falsch ist..slice(0)
einen Klon des Arrays erstellenintersect_safe
, anstatt Indizes zu verfolgen.Wenn Ihre Umgebung ECMAScript 6 Set unterstützt , gibt es eine einfache und vermeintlich effiziente Möglichkeit (siehe Spezifikationslink):
Kürzer, aber weniger lesbar (auch ohne die zusätzliche Kreuzung zu erstellen
Set
):Vermeiden Sie eine neue
Set
ausb
jeder Zeit:Beachten Sie, dass Sie bei Verwendung von Sets nur unterschiedliche Werte erhalten, die daher zu
new Set[1,2,3,3].size
ausgewertet werden3
.quelle
[...setA]
Syntax? Eine spezielle Art von Javascript-Operation?x => new Set(b).has(x)
wiederum Pfeil Funktionb
in eine Reihe jedes Mal ausgeführt wird ? Sie sollten diesen Satz wahrscheinlich in einer Variablen speichern.Verwenden von Underscore.js oder lodash.js
quelle
Mein Beitrag in ES6-Begriffen. Im Allgemeinen wird der Schnittpunkt eines Arrays mit einer unbestimmten Anzahl von Arrays gefunden, die als Argumente bereitgestellt werden.
quelle
[[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8],[4,5,6,7],[4,6]]
und gilt dann.reduce()
. Die erste[0,1,2,3,4,5,6,7,8,9].filter( e => [0,2,4,6,8].includes(e)
Operation wird ausgeführt und das Ergebnis wird das neuep
undc
wird[4,5,6,7]
in der nächsten Runde und setzt sich fort, bis keine mehrc
übrig ist.prototype
unnötig.Ich empfehle die oben genannte prägnante Lösung, die andere Implementierungen bei großen Eingaben übertrifft. Wenn die Leistung bei kleinen Eingaben wichtig ist, überprüfen Sie die folgenden Alternativen.
Alternativen und Leistungsvergleich:
Weitere Implementierungen finden Sie im folgenden Snippet. Unter https://jsperf.com/array-intersection-comparison finden Sie Leistungsvergleiche.
Code-Snippet anzeigen
Ergebnisse in Firefox 53:
Ops / Sek. Auf großen Arrays (10.000 Elemente):
Ops / Sek. Auf kleinen Arrays (100 Elemente):
quelle
intersect([1,2,2,3], [2,3,4,5])
kehrt zurück[2, 2, 3]
.a.filter(b.includes)
. Es sollte erheblich schneller laufen (genau wie Ihr Funktions-Upgrade).Wie wäre es nur mit assoziativen Arrays?
bearbeiten:
quelle
Object.prototype
.d[b[i]] = true;
stattd[b[j]] = true;
(i
nichtj
) sein. Für die Bearbeitung sind jedoch 6 Zeichen erforderlich.So etwas, aber nicht gut getestet.
PS: Der Algorithmus ist nur für Zahlen und normale Zeichenfolgen vorgesehen. Der Schnittpunkt von Arbitary Object Arrays funktioniert möglicherweise nicht.
quelle
Die Leistung der Implementierung von @ atk für sortierte Arrays von Grundelementen kann durch Verwendung von .pop anstelle von .shift verbessert werden.
Ich habe mit jsPerf einen Benchmark erstellt: http://bit.ly/P9FrZK . Es ist ungefähr dreimal schneller, .pop zu verwenden.
quelle
a[aLast] > b[bLast]
mita[aLast].localeCompare(b[bLast]) > 0
(und gleichen mit der weiterelse if
unten) , dann wird dies auf Strings arbeiten..pop
O (1) und.shift()
O (n) istVerwenden von jQuery :
quelle
c = $(b).filter(a);
, aber ich würde nicht empfehlen, sich für diese Art der Array-Manipulation auf jQuery zu verlassen, da in der Dokumentation nur erwähnt wird, dass es für Elemente funktioniert.Bei Arrays, die nur Zeichenfolgen oder Zahlen enthalten, können Sie gemäß einigen der anderen Antworten etwas mit dem Sortieren tun. Für den allgemeinen Fall von Arrays beliebiger Objekte glaube ich nicht, dass Sie es auf lange Sicht vermeiden können. Im Folgenden erhalten Sie den Schnittpunkt einer beliebigen Anzahl von Arrays, die als Parameter für Folgendes bereitgestellt werden
arrayIntersection
:quelle
firstArr
oderfirstArray
und nicht alle Verweise aktualisieren. Fest.Mit ES2015 und Sets ist es ziemlich kurz. Akzeptiert Array-ähnliche Werte wie einen String und entfernt Duplikate.
quelle
Sie könnten eine Verwendung
Set
alsthisArg
vonArray#filter
und nehmenSet#has
als Rückruf.quelle
Eine winzige Änderung an der kleinsten hier (der Filter / IndexOf-Lösung ), nämlich das Erstellen eines Index der Werte in einem der Arrays mithilfe eines JavaScript-Objekts, reduziert diese von O (N * M) auf "wahrscheinlich" lineare Zeit. Quelle1 Quelle2
Dies ist weder die einfachste Lösung (es ist mehr Code als filter + indexOf ) noch die schnellste (wahrscheinlich um einen konstanten Faktor langsamer als intersect_safe () ), scheint aber eine ziemlich gute Balance zu sein. Es ist sehr einfach, bietet aber eine gute Leistung und erfordert keine vorsortierten Eingaben.
quelle
Ein weiterer indizierter Ansatz, der eine beliebige Anzahl von Arrays gleichzeitig verarbeiten kann:
Es funktioniert nur für Werte, die als Zeichenfolgen ausgewertet werden können, und Sie sollten sie als Array wie folgt übergeben:
... aber es akzeptiert Objekte transparent als Parameter oder als eines der zu schneidenden Elemente (wobei immer ein Array gemeinsamer Werte zurückgegeben wird). Beispiele:
EDIT: Ich habe gerade bemerkt, dass dies in gewisser Weise etwas fehlerhaft ist.
Das heißt: Ich habe es codiert, weil ich dachte, dass Eingabearrays selbst keine Wiederholungen enthalten können (wie im angegebenen Beispiel nicht).
Wenn Eingabearrays jedoch Wiederholungen enthalten, führt dies zu falschen Ergebnissen. Beispiel (unter Verwendung der folgenden Implementierung):
Glücklicherweise lässt sich dies leicht beheben, indem einfach die Indizierung der zweiten Ebene hinzugefügt wird. Das ist:
Veränderung:
durch:
...und:
durch:
Vollständiges Beispiel:
quelle
var v =
Hinzufügen der Zeileif (typeof v == 'function') continue;
wird das Hinzufügen von Funktionen zu den Ergebnissen übersprungen. Vielen Dank!if (typeof v == 'function')
, dann können wir seine Stringifikation (v.toString()
) als Schlüssel für den Index verwenden. Aber wir müssen etwas tun, um ihn intakt zu halten Am einfachsten ist es, einfach die ursprüngliche Funktion als Wert anstelle eines einfachen booleschen wahren Werts zuzuweisen. In diesem Fall sollte jedoch auch die neueste Deindexierung geändert werden, um diesen Zustand zu erkennen und den richtigen Wert (die Funktion) wiederherzustellen.Sie können verwenden (für alle Browser außer IE):
oder für IE:
quelle
quelle
Mit einigen Einschränkungen für Ihre Daten können Sie dies linear tun Zeit !
Für positive Ganzzahlen : Verwenden Sie ein Array, das die Werte einem Booleschen Wert "gesehen / nicht gesehen" zuordnet.
Es gibt eine ähnliche Technik für Objekte : Nehmen Sie einen Dummy-Schlüssel, setzen Sie ihn für jedes Element in Array1 auf "true" und suchen Sie diesen Schlüssel in Elementen von Array2. Räumen Sie auf, wenn Sie fertig sind.
Natürlich müssen Sie sicher sein, dass der Schlüssel vorher nicht angezeigt wurde, sonst zerstören Sie Ihre Daten ...
quelle
Ich werde mit dem beitragen, was für mich am besten funktioniert hat:
quelle
"indexOf" für IE 9.0, Chrome, Firefox, Oper,
quelle
quelle
Ein funktionaler Ansatz mit ES2015
Ein funktionaler Ansatz muss in Betracht ziehen, nur reine Funktionen ohne Nebenwirkungen zu verwenden, von denen jede nur einen einzelnen Job betrifft.
Diese Einschränkungen verbessern die Zusammensetzbarkeit und Wiederverwendbarkeit der beteiligten Funktionen.
Bitte beachten Sie, dass der native
Set
Typ verwendet wird, der eine vorteilhafte Suchleistung bietet.Vermeiden Sie Duplikate
Offensichtlich
Array
bleiben wiederholt vorkommende Elemente aus dem ersten erhalten, während das zweite nichtArray
dupliziert wird. Dies kann das gewünschte Verhalten sein oder auch nicht. Wenn Sie ein eindeutiges Ergebnis benötigen, wenden Sie einfachdedupe
das erste Argument an:Berechnen Sie den Schnittpunkt einer beliebigen Anzahl von
Array
sWenn Sie den Schnittpunkt einer beliebigen Anzahl von
Array
s berechnen möchten, komponieren Sie einfachintersect
mitfoldl
. Hier ist eine Komfortfunktion:quelle
(expr ? true : false)
ist redundant. Verwenden Sie nur,expr
wenn keine tatsächlichen Booleschen Werte benötigt werden, sondern nur "wahr" / "falsch".Der Einfachheit halber:
Leistungen:
Nachteile:
Sie möchten dies nicht für 3D-Engine- oder Kernel-Arbeiten verwenden, aber wenn Sie Probleme haben, dies in einer ereignisbasierten App auszuführen, hat Ihr Design größere Probleme.
quelle
.reduce
um eine Karte zu erstellen und.filter
die Kreuzung zu finden.delete
Innerhalb von.filter
können wir das zweite Array so behandeln, als wäre es eine eindeutige Menge.Ich finde diesen Ansatz ziemlich einfach zu überlegen. Es arbeitet in konstanter Zeit.
quelle
Dies ist neben list1.filter (n => list2.includes (n)) wahrscheinlich die einfachste.
quelle
Wenn es mehrere Arrays schneiden muss:
quelle
ES6-Stil auf einfache Weise.
Beispiel:
quelle
Ich habe eine Schnittfunktion geschrieben, die sogar Schnittpunkte von Arrays von Objekten basierend auf bestimmten Eigenschaften dieser Objekte erkennen kann.
Zum Beispiel,
und wir wollen eine Schnittmenge basierend auf der
id
Eigenschaft, dann sollte die Ausgabe sein:Daher lautet die Funktion für dasselbe (Hinweis: ES6-Code):
und Sie können die Funktion aufrufen als:
Beachten Sie auch: Diese Funktion findet Schnittpunkte, wenn das erste Array das primäre Array ist und das Schnittpunktergebnis daher das des primären Arrays ist.
quelle
Denken Sie, dass dies mit der Zeit O (Array1 + Array2) schneller sein wird, vorausgesetzt, map.has () ist ~ O (1). Bitte korrigieren Sie mich, wenn Sie falsch liegen.
quelle
Hier ist die Implementierung von underscore.js :
Quelle: http://underscorejs.org/docs/underscore.html#section-62
quelle