Was ist der präziseste und effizienteste Weg, um herauszufinden, ob ein JavaScript-Array einen Wert enthält?
Dies ist der einzige Weg, den ich kenne:
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (a[i] === obj) {
return true;
}
}
return false;
}
Gibt es einen besseren und prägnanteren Weg, um dies zu erreichen?
Dies hängt sehr eng mit der Frage zum Stapelüberlauf zusammen. Der beste Weg, um ein Element in einem JavaScript-Array zu finden? Hiermit wird das Suchen von Objekten in einem Array mithilfe von indexOf
.
~[1,2,3].indexOf(4)
Gibt 0 zurück, was als falsch ausgewertet wird, während~[1,2,3].indexOf(3)
-3 zurückgegeben wird, was als wahr ausgewertet wird.~
ist nicht das, was Sie verwenden möchten, um in einen Booleschen Wert zu konvertieren!
. In diesem Fall möchten Sie jedoch die Gleichheit mit -1 überprüfen, damit die Funktion möglicherweisereturn [1,2,3].indexOf(3) === -1;
~
nicht binär endet. Sie invertiert jedes Bit des Werts einzeln.[1,2,3].indexOf(4)
wird tatsächlich -1 zurückgeben . Wie @mcfedr hervorhob,~
handelt es sich um den bitweisen NOT-Operator , siehe ES5 11.4.8. Da die binäre Darstellung von nur-1
aus Einsen besteht, ist das Komplement0
, das als falsch ausgewertet wird. Das Komplement einer anderen Zahl ist ungleich Null, daher wahr. Funktioniert also~
einwandfrei und wird oft in Verbindung mit verwendetindexOf
.[[1,2],[3,4]].includes([3,4])
?Antworten:
Moderne Browser haben
Array#includes
, was genau das tut und von allen außer IE weitgehend unterstützt wird:Sie können auch verwenden
Array#indexOf
, was weniger direkt ist, aber keine Polyfüllungen für veraltete Browser erfordert.Viele Frameworks bieten auch ähnliche Methoden an:
$.inArray(value, array, [fromIndex])
_.contains(array, value)
(auch als_.include
und alias_.includes
)dojo.indexOf(array, value, [fromIndex, findLast])
array.indexOf(value)
array.indexOf(value)
findValue(array, value)
array.indexOf(value)
Ext.Array.contains(array, value)
_.includes(array, value, [from])
(ist_.contains
vor 4.0.0)R.includes(value, array)
Beachten Sie, dass einige Frameworks dies als Funktion implementieren, während andere die Funktion dem Array-Prototyp hinzufügen.
quelle
Array.include
dass ein Boolescherarray.indexOf(object) != -1
inArray
ist ein schrecklicher Name für eine Funktion, die den Index des Elements zurückgibt, und-1
wenn es nicht existiert. Ich würde erwarten, dass ein Boolescher Wert zurückgegeben wird.Update von 2019: Diese Antwort stammt aus dem Jahr 2008 (11 Jahre alt!) Und ist für die moderne JS-Nutzung nicht relevant. Die versprochene Leistungsverbesserung basierte auf einem Benchmark, der in den damaligen Browsern durchgeführt wurde. Es ist möglicherweise für moderne JS-Ausführungskontexte nicht relevant. Wenn Sie eine einfache Lösung benötigen, suchen Sie nach anderen Antworten. Wenn Sie die beste Leistung benötigen, messen Sie sich selbst in den relevanten Ausführungsumgebungen.
Wie andere gesagt haben, ist die Iteration durch das Array wahrscheinlich der beste Weg, aber es wurde bewiesen, dass eine abnehmende
while
Schleife der schnellste Weg ist, um in JavaScript zu iterieren. Daher möchten Sie Ihren Code möglicherweise wie folgt umschreiben:Natürlich können Sie auch den Array-Prototyp erweitern:
Und jetzt können Sie einfach Folgendes verwenden:
quelle
for (o in array)
der nicht gemacht werden sollte, wenn man das Array im AllgemeinenindexOf
Vielleicht, aber es ist eine "JavaScript-Erweiterung des ECMA-262-Standards; als solche ist sie möglicherweise in anderen Implementierungen des Standards nicht vorhanden."Beispiel:
AFAICS Microsoft bietet keine Alternative dazu an, aber Sie können Arrays in Internet Explorer (und anderen Browsern, die dies nicht unterstützen
indexOf
) ähnliche Funktionen hinzufügen, wenn Sie dies möchten, wie eine schnelle Google-Suche zeigt (z. B. diese) ).quelle
ECMAScript 7 wird vorgestellt
Array.prototype.includes
.Es kann folgendermaßen verwendet werden:
Es akzeptiert auch ein optionales zweites Argument
fromIndex
:Im Gegensatz zu
indexOf
, die verwendet strikte Gleichheit Vergleich ,includes
vergleicht mit SameValueZero Gleichheit Algorithmus. Das bedeutet, dass Sie erkennen können, ob ein Array Folgendes enthältNaN
:Auch im Gegensatz zu
indexOf
,includes
nicht überspringen Indizes fehlen:Derzeit ist es noch ein Entwurf, kann aber mehrfach ausgefüllt werden , damit er in allen Browsern funktioniert.
quelle
Die Top-Antworten setzen primitive Typen voraus. Wenn Sie jedoch herausfinden möchten, ob ein Array ein Objekt mit einem bestimmten Merkmal enthält, ist Array.prototype.some () eine sehr elegante Lösung:
Das Schöne daran ist, dass die Iteration abgebrochen wird, sobald das Element gefunden wurde, sodass unnötige Iterationszyklen verschont bleiben.
Außerdem passt es gut in eine
if
Anweisung, da es einen Booleschen Wert zurückgibt:* Wie Jamess im Kommentar betonte, wird zum Zeitpunkt dieser Antwort im September 2018
Array.prototype.some()
die Support-Tabelle von caniuse.com vollständig unterstütztquelle
Arrow functions
in diesem Beispiel nicht so gut unterstützt werden. Weitere Details finden Sie hier: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Angenommen, Sie haben ein Array wie folgt definiert:
Im Folgenden finden Sie drei Möglichkeiten, um zu überprüfen, ob dort eine
3
vorhanden ist. Alle von ihnen kehren entwedertrue
oder zurückfalse
.Native Array-Methode (seit ES2016) ( Kompatibilitätstabelle )
Als benutzerdefinierte Array-Methode (vor ES2016)
Einfache Funktion
quelle
Hier ist eine JavaScript 1.6-kompatible Implementierung von
Array.indexOf
:quelle
[].indexOf
ist eine Abkürzung fürArray.prototype.indexOf
. Wir paranoid-defensiven Javascript-Programmierer vermeiden es um jeden Preis, native Prototypen zu erweitern.[].indexOf
ein neues Array erstellt und dann zugegriffenindexOf
, währendArray.prototype.indexOf
nur direkt auf den Prototyp zugegriffen wird?[].indexOf === Array.prototype.indexOf
(probiere es in FireBug aus), aber umgekehrt[].indexOf !== Array.indexOf
.Verwenden:
quelle
x ? true : false
ist normalerweise redundant. Es ist hier.array.indexOf(search) >= 0
ist schon ein Boolescher Wert. Einfachreturn array.indexOf(search) >= 0
.Das Erweitern des JavaScript-
Array
Objekts ist eine wirklich schlechte Idee, da Sie neue Eigenschaften (Ihre benutzerdefinierten Methoden) infor-in
Schleifen einfügen, die vorhandene Skripts beschädigen können. Vor einigen Jahren mussten die Autoren der Prototype- Bibliothek ihre Bibliotheksimplementierung überarbeiten, um genau diese Dinge zu entfernen.Wenn Sie sich keine Gedanken über die Kompatibilität mit anderem JavaScript machen müssen, das auf Ihrer Seite ausgeführt wird, versuchen Sie es. Andernfalls würde ich die umständlichere, aber sicherere Lösung für freistehende Funktionen empfehlen.
quelle
Einzeiler:
quelle
array.filter(e=>e==x).length > 0
ist gleichbedeutend mitarray.some(e=>e==x)
abersome
effizienterWenn Sie für eine Sekunde über den Tellerrand hinaus denken und diesen Aufruf viele Male ausführen, ist es weitaus effizienter,
ein assoziatives Array undeine Map zu verwenden, um mithilfe einer Hash-Funktion nachzuschlagen.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
quelle
Ich benutze folgendes:
quelle
Array.prototype.some () wurde in der 5. Ausgabe zum ECMA-262-Standard hinzugefügt
quelle
contains = (a, obj) => a.some((element) => element === obj))
Eine hoffentlich schnellere bidirektionale
indexOf
/lastIndexOf
Alternative2015
Während die neue Methode enthält, ist sehr nett, aber die Unterstützung ist im Moment Null.
Es ist lange her, dass ich mir überlegt habe, wie ich die langsamen Funktionen indexOf / lastIndexOf ersetzen kann.
Es wurde bereits ein performanter Weg gefunden, der sich die besten Antworten ansieht. Von diesen habe ich die
contains
von @Damir Zekic gepostete Funktion ausgewählt, die die schnellste sein sollte. Es heißt aber auch, dass die Benchmarks aus dem Jahr 2008 stammen und daher veraltet sind.Ich bevorzuge es
while
auchfor
, aber aus keinem bestimmten Grund habe ich das Schreiben der Funktion mit einer for-Schleife beendet. Es könnte auch mit einem gemacht werdenwhile --
.Ich war neugierig, ob die Iteration viel langsamer war, wenn ich dabei beide Seiten des Arrays überprüfe. Anscheinend nein, und so ist diese Funktion ungefähr zweimal schneller als die am besten bewerteten. Offensichtlich ist es auch schneller als das native. Dies in einer realen Umgebung, in der Sie nie wissen, ob sich der gesuchte Wert am Anfang oder am Ende des Arrays befindet.
Wenn Sie wissen, dass Sie gerade ein Array mit einem Wert verschoben haben, bleibt die Verwendung von lastIndexOf wahrscheinlich die beste Lösung. Wenn Sie jedoch große Arrays durchlaufen müssen und das Ergebnis überall sein kann, kann dies eine solide Lösung sein, um die Dinge schneller zu machen.
Bidirektionaler IndexOf / lastIndexOf
Leistungstest
http://jsperf.com/bidirectionalindexof
Als Test habe ich ein Array mit 100.000 Einträgen erstellt.
Drei Abfragen: am Anfang, in der Mitte und am Ende des Arrays.
Ich hoffe, Sie finden das auch interessant und testen die Leistung.
Hinweis: Wie Sie sehen, habe ich die
contains
Funktion geringfügig geändert , um die Ausgabe von indexOf & lastIndexOf widerzuspiegeln (also im Grunde genommentrue
mitindex
undfalse
mit-1
). Das sollte nicht schaden.Die Array-Prototyp-Variante
Die Funktion kann auch leicht geändert werden, um true oder false oder sogar das Objekt, die Zeichenfolge oder was auch immer zurückzugeben.
Und hier ist die
while
Variante:Wie ist das möglich?
Ich denke, dass die einfache Berechnung, um den reflektierten Index in einem Array zu erhalten, so einfach ist, dass sie zweimal schneller ist als eine tatsächliche Schleifeniteration.
Hier ist ein komplexes Beispiel, das drei Überprüfungen pro Iteration durchführt. Dies ist jedoch nur mit einer längeren Berechnung möglich, die zu einer Verlangsamung des Codes führt.
http://jsperf.com/bidirectionalindexof/2
quelle
Performance
Heute 2020.01.07 führe ich Tests auf MacOs HighSierra 10.13.6 unter Chrome v78.0.0, Safari v13.0.4 und Firefox v71.0.0 für 15 ausgewählte Lösungen durch. Schlussfolgerungen
JSON
,Set
und überraschendfind
(K, N, O) sind langsamsten auf allen Browsernincludes
(F) ist nur auf chrom schnellfor
(C, D) undindexOf
(G, H) basierenden Lösungen sind in allen Browsern auf kleinen und großen Arrays recht schnell, sodass sie wahrscheinlich die beste Wahl für eine effiziente Lösung sindfor
(C, D, E) ähnliche Ergebnisse liefern (~ 630 ops / s - aber das E auf Safari und Firefox war 10- 20% langsamer als C und D)Ergebnisse
Einzelheiten
Ich führe 2 Testfälle durch: für ein Array mit 10 Elementen und ein Array mit 1 Million Elementen. In beiden Fällen setzen wir das gesuchte Element in die Mitte des Arrays.
Code-Snippet anzeigen
Array klein - 10 Elemente
Sie können HIER Tests in Ihrer Maschine durchführen
Array groß - 1.000.000 Elemente
Sie können HIER Tests in Ihrer Maschine durchführen
quelle
Wenn Sie JavaScript 1.6 oder höher (Firefox 1.5 oder höher) verwenden, können Sie Array.indexOf verwenden . Andernfalls werden Sie wahrscheinlich etwas Ähnliches wie Ihren ursprünglichen Code erhalten.
quelle
Gibt den Array-Index zurück, wenn er gefunden wurde, oder -1, wenn er nicht gefunden wurde
quelle
Wir verwenden dieses Snippet (funktioniert mit Objekten, Arrays, Strings):
Verwendungszweck:
quelle
Wenn Sie wiederholt prüfen, ob ein Objekt in einem Array vorhanden ist, sollten Sie dies möglicherweise untersuchen
contains(a, obj)
.quelle
Lösung, die in allen modernen Browsern funktioniert:
Verwendungszweck:
IE6 + Lösung:
Verwendungszweck:
Warum verwenden
JSON.stringify
?Array.indexOf
undArray.includes
(wie auch die meisten Antworten hier) nur nach Referenz und nicht nach Wert vergleichen.Bonus
Nicht optimierter ES6-Einzeiler:
Hinweis: Das Vergleichen von Objekten nach Wert funktioniert besser, wenn die Schlüssel in derselben Reihenfolge vorliegen. Aus Sicherheitsgründen können Sie die Schlüssel daher zuerst mit einem Paket wie diesem sortieren: https://www.npmjs.com/package/sort-keys
Die
contains
Funktion wurde mit einer Perf-Optimierung aktualisiert . Vielen Dank an itinance für den Hinweis.quelle
includes
Funktion wurde mit Ihrem Vorschlag aktualisiert . Ich habe jsperf mit meiner Funktion ausgeführt. Es ist ungefähr 5x langsamer als das von lodash. Obwohl lodash nach Wert nicht vergleichen und nicht finden kann ,{a: 1}
in[{a: 1}]
. Ich weiß nicht, ob eine Bibliothek das tut. Aber ich bin gespannt, ob es eine performantere und nicht wahnsinnig komplexe Art gibt, dies zu tun.contains([{ a: 1, b: 2 }], { b: 2, a: 1 })
da die Zeichenfolgenobjekte die Reihenfolge der Eigenschaften beibehalten.sort-keys
Notiz unten hinzugefügtVerwenden lodash ist einige Funktion.
Es ist präzise, genau und bietet hervorragende plattformübergreifende Unterstützung.
Die akzeptierte Antwort entspricht nicht einmal den Anforderungen.
Anforderungen: Empfehlen Sie die präziseste und effizienteste Methode, um herauszufinden, ob ein JavaScript-Array ein Objekt enthält.
Akzeptierte Antwort:
Meine Empfehlung:
Anmerkungen:
$ .inArray funktioniert gut, um festzustellen, ob ein Skalarwert in einem Array von Skalaren vorhanden ist ...
... aber die Frage fragt eindeutig nach einer effizienten Methode, um festzustellen, ob ein Objekt in einem Array enthalten ist.
Um sowohl Skalare als auch Objekte zu handhaben, können Sie Folgendes tun:
quelle
ECMAScript 6 hat einen eleganten Vorschlag zum Finden.
Hier ist die MDN-Dokumentation dazu .
Die Suchfunktion funktioniert folgendermaßen.
Sie können dies in ECMAScript 5 und darunter verwenden, indem Sie die Funktion definieren .
quelle
Während
array.indexOf(x)!=-1
die knappste Art und Weise, dies zu tun (und wird von Nicht-Internet Explorer - Browser für mehr als zehn Jahre ... unterstützt), ist es nicht O (1), sondern O (N), das ist schrecklich. Wenn Ihr Array nicht wird sich ändern, können Sie Ihr Array in eine Hash - Tabelle umwandeln kann, dann tuntable[x]!==undefined
oder===undefined
:Demo:
(Obwohl Sie eine Array.prototype.contains erstellen können, um ein Array "einzufrieren" und eine Hashtabelle in this._cache in zwei Zeilen zu speichern, würde dies leider zu falschen Ergebnissen führen, wenn Sie Ihr Array später bearbeiten. JavaScript hat nicht genügend Hooks Lassen Sie diesen Status im Gegensatz zu Python beibehalten.)
quelle
Man kann Set verwenden , das die Methode "has ()" hat:
quelle
return proxy.has(obj)
ist viel sauberer als zwei Zeilen mit if-else-Aussage hierfunction contains(arr, obj) { return new Set(arr).has(obj); }
Verwenden:
Demo
Um genau zu wissen, was
tilde
~
an dieser Stelle zu tun ist, lesen Sie diese Frage. Was macht eine Tilde, wenn sie einem Ausdruck vorausgeht? .quelle
OK, Sie können einfach Ihre optimieren Code , um das Ergebnis zu erhalten!
Es gibt viele Möglichkeiten, dies zu tun, die sauberer und besser sind, aber ich wollte nur Ihr Muster erhalten und auf dieses anwenden, indem Sie
JSON.stringify
in Ihrem Fall einfach so etwas tun:quelle
contains([{ a: 1, b: 2 }], { b: 2, a: 1 })
da die Zeichenfolgenobjekte die Reihenfolge der Eigenschaften beibehalten.Auf keinen Fall das Beste, aber ich wurde nur kreativ und erweiterte das Repertoire.
Verwenden Sie dies nicht
quelle
Überrascht, dass dieser Frage immer noch nicht die neueste Syntax hinzugefügt wurde, füge ich meine 2 Cent hinzu.
Angenommen, wir haben ein Array von Objekten arrObj und möchten darin obj suchen.
Array.prototype. indexOf -> (gibt index oder -1 zurück ) wird im Allgemeinen zum Suchen des Index des Elements im Array verwendet. Dies kann auch zum Suchen von Objekten verwendet werden, funktioniert jedoch nur, wenn Sie einen Verweis auf dasselbe Objekt übergeben.
Array.prototype. enthält -> (gibt true oder false zurück )
Array.prototype. find -> (nimmt einen Rückruf entgegen und gibt den ersten Wert / das erste Objekt zurück, das in CB true zurückgibt).
Array.prototype. findIndex -> (nimmt einen Rückruf entgegen und gibt den Index des ersten Werts / Objekts zurück, der in CB true zurückgibt).
Da find und findIndex einen Rückruf annehmen, können wir jedes Objekt (auch wenn wir keine Referenz haben) aus dem Array abrufen, indem wir die wahre Bedingung kreativ festlegen.
quelle
Eine einfache Lösung für diese Anforderung ist die Verwendung
find()
Wenn Sie eine Reihe von Objekten wie unten haben,
Anschließend können Sie überprüfen, ob das Objekt mit Ihrem Wert bereits vorhanden ist oder nicht
Wenn die Daten null sind, gibt es keinen Administrator. Andernfalls wird das vorhandene Objekt wie unten angegeben zurückgegeben.
Dann können Sie den Index dieses Objekts im Array finden und das Objekt mit dem folgenden Code ersetzen.
Sie erhalten Wert wie unten
hoffe, das wird jedem helfen.
quelle
quelle