Was ist der schnellste Weg, um festzustellen, ob ein Wert in einer Liste vorhanden ist (eine Liste mit Millionen von Werten) und wie der Index lautet?
Ich weiß, dass alle Werte in der Liste wie in diesem Beispiel eindeutig sind.
Die erste Methode, die ich versuche, ist (3,8 Sekunden in meinem realen Code):
a = [4,2,3,1,5,6]
if a.count(7) == 1:
b=a.index(7)
"Do something with variable b"
Die zweite Methode, die ich versuche, ist (2x schneller: 1,9 Sekunden für meinen echten Code):
a = [4,2,3,1,5,6]
try:
b=a.index(7)
except ValueError:
"Do nothing"
else:
"Do something with variable b"
Vorgeschlagene Methoden vom Stack Overflow-Benutzer (2,74 Sek. Für meinen echten Code):
a = [4,2,3,1,5,6]
if 7 in a:
a.index(7)
In meinem realen Code dauert die erste Methode 3,81 Sekunden und die zweite Methode 1,88 Sekunden. Es ist eine gute Verbesserung, aber:
Ich bin ein Anfänger mit Python / Scripting und gibt es eine schnellere Möglichkeit, die gleichen Dinge zu tun und mehr Verarbeitungszeit zu sparen?
Spezifischere Erklärung für meine Anwendung:
In der Blender-API kann ich auf eine Liste von Partikeln zugreifen:
particles = [1, 2, 3, 4, etc.]
Von dort aus kann ich auf die Position eines Partikels zugreifen:
particles[x].location = [x,y,z]
Und für jedes Partikel teste ich, ob ein Nachbar existiert, indem ich jeden Partikelort wie folgt suche:
if [x+1,y,z] in particles.location
"Find the identity of this neighbour particle in x:the particle's index
in the array"
particles.index([x+1,y,z])
quelle
bisect
ModulAntworten:
Der klarste und schnellste Weg, dies zu tun.
Sie können auch die Verwendung von a in Betracht ziehen
set
, aber das Erstellen dieses Satzes aus Ihrer Liste kann mehr Zeit in Anspruch nehmen, als ein schnellerer Mitgliedschaftstest spart. Der einzige Weg, um sicher zu sein, ist ein gutes Benchmarking. (Dies hängt auch davon ab, welche Vorgänge Sie benötigen.)quelle
Wie von anderen angegeben,
in
kann es bei großen Listen sehr langsam sein. Hier einige Vergleiche der Leistungen fürin
,set
undbisect
. Beachten Sie, dass die Zeit (in Sekunden) in der Protokollskala angegeben ist.Code zum Testen:
quelle
import random / import bisect / import matplotlib.pyplot as plt
und rufen Sie dann an:profile()
range()
Objekt nicht. Überprüfen Sie bei der Verwendungvar in [integer list]
, ob einrange()
Objekt dieselbe Sequenz modellieren kann. Sehr nahe an der Leistung eines Sets, aber prägnanter.Sie könnten Ihre Artikel in eine
set
. Set-Lookups sind sehr effizient.Versuchen:
Bearbeiten In einem Kommentar sagen Sie, dass Sie den Index des Elements erhalten möchten. Leider haben Mengen keine Vorstellung von der Elementposition. Eine Alternative besteht darin, Ihre Liste vorab zu sortieren und dann jedes Mal die binäre Suche zu verwenden, wenn Sie ein Element suchen müssen.
quelle
Verwendungszweck
Ich glaube, dies ist der schnellste Weg, um festzustellen, ob sich ein ausgewählter Wert in einem Array befindet.
quelle
return 'a' in a
?o='--skip'; o in ("--skip-ias"); # returns True !
in
Operator testet auf die gleiche Weise die Teilstring-Mitgliedschaft. Der verwirrende Teil hier ist wahrscheinlich, dass("hello")
es sich nicht um ein einwertiges Tupel handelt, während("hello",)
- das Komma den Unterschied macht.o in ("--skip-ias",)
istFalse
wie erwartet.Dies ist nur dann eine gute Idee, wenn sich a nicht ändert. Daher können wir den dict () - Teil einmal ausführen und ihn dann wiederholt verwenden. Wenn sich a ändert, geben Sie bitte detaillierter an, was Sie tun.
quelle
Die ursprüngliche Frage war:
Es gibt also zwei Dinge zu finden:
Zu diesem Zweck habe ich den @ xslittlegrass-Code geändert, um in allen Fällen Indizes zu berechnen, und eine zusätzliche Methode hinzugefügt.
Ergebnisse
Methoden sind:
Die Ergebnisse zeigen, dass Methode 5 die schnellste ist.
Interessanterweise sind die try- und die set- Methode zeitlich gleichwertig.
Testcode
quelle
Es hört sich so an, als würde Ihre Anwendung von der Verwendung einer Bloom Filter-Datenstruktur profitieren.
Kurz gesagt, eine Bloom-Filter-Suche kann Ihnen sehr schnell sagen, ob ein Wert in einem Satz definitiv NICHT vorhanden ist. Andernfalls können Sie langsamer nachschlagen, um den Index eines Werts zu erhalten, der möglicherweise in der Liste enthalten ist. Wenn Ihre Anwendung also dazu neigt, das Ergebnis "nicht gefunden" viel häufiger als das Ergebnis "gefunden" zu erhalten, wird möglicherweise eine Beschleunigung durch Hinzufügen eines Bloom-Filters angezeigt.
Für Details bietet Wikipedia einen guten Überblick über die Funktionsweise von Bloom-Filtern, und eine Websuche nach "Python Bloom Filter Library" bietet mindestens einige nützliche Implementierungen.
quelle
Beachten Sie, dass der
in
Operator nicht nur Gleichheit (==
), sondern auch Identität (is
) testet. Diein
Logik fürlist
s entspricht in etwa der folgenden (sie ist tatsächlich in C und nicht in Python geschrieben, zumindest in CPython):In den meisten Fällen ist dieses Detail irrelevant, aber unter bestimmten Umständen kann es einen Python-Neuling überraschen, der beispielsweise
numpy.NAN
die ungewöhnliche Eigenschaft hat, nicht gleich sich selbst zu sein :Um zwischen diesen ungewöhnlichen Fällen zu unterscheiden, können Sie Folgendes verwenden
any()
:Beachten Sie die
in
Logik fürlist
s mitany()
wäre:Ich möchte jedoch betonen, dass dies ein Randfall ist und in den allermeisten Fällen der
in
Operator hochoptimiert ist und natürlich genau das, was Sie wollen (entweder mit alist
oder mit aset
).quelle
Oder verwenden Sie
__contains__
:Demo:
quelle
Die Lösung von @Winston Ewert führt zu einer großen Beschleunigung für sehr große Listen. Diese Stackoverflow-Antwort zeigt jedoch an, dass das Konstrukt try: / Except : / else: verlangsamt wird, wenn der Zweig Except häufig erreicht wird. Eine Alternative besteht darin, die
.get()
Methode für das Diktat zu nutzen:Die
.get(key, default)
Methode ist nur für den Fall gedacht, dass Sie nicht garantieren können, dass ein Schlüssel im Diktat enthalten ist. Wenn Schlüssel ist vorhanden, gibt sie den Wert (wie esdict[key]
), aber wenn es nicht der Fall,.get()
kehrt Ihr Standardwert (hierNone
). In diesem Fall müssen Sie sicherstellen, dass der ausgewählte Standard nicht aktiviert ista
.quelle
Dies ist nicht der Code, sondern der Algorithmus für eine sehr schnelle Suche.
Wenn Ihre Liste und der gesuchte Wert alle Zahlen sind, ist dies ziemlich einfach. Wenn Zeichenfolgen: Schauen Sie unten:
Wenn Sie auch die ursprüngliche Position Ihrer Nummer benötigen, suchen Sie diese in der zweiten Indexspalte.
Wenn Ihre Liste nicht aus Zahlen besteht, funktioniert die Methode weiterhin und ist am schnellsten. Möglicherweise müssen Sie jedoch eine Funktion definieren, mit der Zeichenfolgen verglichen / sortiert werden können.
Dies erfordert natürlich die Investition der sorted () -Methode, aber wenn Sie dieselbe Liste weiterhin zur Überprüfung verwenden, kann es sich lohnen.
quelle
Da die Frage nicht immer als der schnellste technische Weg verstanden werden soll, schlage ich immer den einfachsten und schnellsten Weg zum Verstehen / Schreiben vor: ein Listenverständnis, einzeilig
Ich hatte eine
list_to_search_in
mit allen Elementen und wollte die Indizes der Elemente in der zurückgebenlist_from_which_to_search
.Dies gibt die Indizes in einer schönen Liste zurück.
Es gibt andere Möglichkeiten, um dieses Problem zu überprüfen. Das Listenverständnis ist jedoch schnell genug, um ein Problem zu lösen.
quelle
Für mich waren es 0,030 Sekunden (real), 0,026 Sekunden (Benutzer) und 0,004 Sekunden (sys).
quelle
Code zum Überprüfen, ob zwei Elemente in einem Array vorhanden sind, deren Produkt gleich k ist:
quelle