Antworten:
[i for i, v in enumerate(L) if v[0] == 53]
Sie können ein Listenverständnis verwenden :
>>> a = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
>>> [x[0] for x in a]
[1, 22, 53, 44]
>>> [x[0] for x in a].index(53)
2
Ein Generatorausdruck ist wahrscheinlich die performanteste und einfachste Lösung für Ihr Problem:
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
result = next((i for i, v in enumerate(l) if v[0] == 53), None)
# 2
Es gibt mehrere Antworten, die eine einfache Lösung für diese Frage mit Listenverständnis bieten. Diese Antworten sind zwar vollkommen richtig, aber nicht optimal. Abhängig von Ihrem Anwendungsfall können einige einfache Änderungen erhebliche Vorteile haben.
Das Hauptproblem bei der Verwendung eines Listenverständnisses für diesen Anwendungsfall besteht darin, dass die gesamte Liste verarbeitet wird, obwohl Sie nur 1 Element finden möchten .
Python bietet ein einfaches Konstrukt, das hier ideal ist. Es wird der Generatorausdruck genannt . Hier ist ein Beispiel:
# Our input list, same as before
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
# Call next on our generator expression.
next((i for i, v in enumerate(l) if v[0] == 53), None)
Wir können erwarten, dass diese Methode im Wesentlichen die gleiche Leistung wie das Listenverständnis in unserem trivialen Beispiel erbringt. Was ist jedoch, wenn wir mit einem größeren Datensatz arbeiten? Hier kommt der Vorteil der Generatormethode ins Spiel. Anstatt eine neue Liste zu erstellen, verwenden wir Ihre vorhandene Liste als iterable und verwenden sienext()
, um das erste Element von unserem Generator abzurufen.
Schauen wir uns an, wie sich diese Methoden bei einigen größeren Datenmengen unterschiedlich verhalten. Dies sind große Listen mit 10000000 + 1 Elementen, wobei unser Ziel am Anfang (am besten) oder am Ende (am schlechtesten) liegt. Wir können anhand des folgenden Listenverständnisses überprüfen, ob beide Listen gleich gut funktionieren:
worst_case = ([(False, 'F')] * 10000000) + [(True, 'T')]
print [i for i, v in enumerate(worst_case) if v[0] is True]
# [10000000]
# 2 function calls in 3.885 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 3.885 3.885 3.885 3.885 so_lc.py:1(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
best_case = [(True, 'T')] + ([(False, 'F')] * 10000000)
print [i for i, v in enumerate(best_case) if v[0] is True]
# [0]
# 2 function calls in 3.864 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 3.864 3.864 3.864 3.864 so_lc.py:1(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
Hier ist meine Hypothese für Generatoren: Wir werden sehen, dass Generatoren im besten Fall eine deutlich bessere Leistung erbringen, im schlimmsten Fall jedoch ähnlich. Dieser Leistungsgewinn ist hauptsächlich auf die Tatsache zurückzuführen, dass der Generator träge ausgewertet wird, was bedeutet, dass nur berechnet wird, was erforderlich ist, um einen Wert zu erhalten.
# 10000000
# 5 function calls in 1.733 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 2 1.455 0.727 1.455 0.727 so_lc.py:10(<genexpr>)
# 1 0.278 0.278 1.733 1.733 so_lc.py:9(<module>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
# 1 0.000 0.000 1.455 1.455 {next}
best_case = [(True, 'T')] + ([(False, 'F')] * 10000000)
print next((i for i, v in enumerate(best_case) if v[0] == True), None)
# 0
# 5 function calls in 0.316 seconds
#
# Ordered by: standard name
#
# ncalls tottime percall cumtime percall filename:lineno(function)
# 1 0.316 0.316 0.316 0.316 so_lc.py:6(<module>)
# 2 0.000 0.000 0.000 0.000 so_lc.py:7(<genexpr>)
# 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
# 1 0.000 0.000 0.000 0.000 {next}
WAS?! Der beste Fall bläst weg das Listenverständnis zum Erliegen, aber ich hatte nicht erwartet, dass unser schlechtester Fall das Listenverständnis in einem solchen Ausmaß übertrifft. Wie ist das? Ehrlich gesagt konnte ich nur ohne weitere Forschung spekulieren.
Nehmen Sie all dies mit einem Körnchen Salz, ich habe hier keine robuste Profilierung durchgeführt, nur einige sehr grundlegende Tests. Dies sollte ausreichen, um zu erkennen, dass ein Generatorausdruck für diese Art der Listensuche leistungsfähiger ist.
Beachten Sie, dass dies alles grundlegende, integrierte Python ist. Wir müssen nichts importieren oder Bibliotheken verwenden.
Ich habe diese Technik zum ersten Mal für die Suche im Udacity cs212- Kurs mit Peter Norvig gesehen.
Ihre Tupel sind im Grunde Schlüssel-Wert-Paare - eine Python - dict
also:
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
val = dict(l)[53]
Bearbeiten - aha, Sie sagen, Sie möchten den Indexwert von (53, "xuxa"). Wenn dies wirklich das ist, was Sie wollen, müssen Sie die ursprüngliche Liste durchlaufen oder vielleicht ein komplizierteres Wörterbuch erstellen:
d = dict((n,i) for (i,n) in enumerate(e[0] for e in l))
idx = d[53]
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")] val = dict(l).get(53)
Hmm ... nun, der einfache Weg, der mir in den Sinn kommt, besteht darin, ihn in ein Diktat umzuwandeln
d = dict(thelist)
und Zugang d[53]
.
EDIT : Ups, falsch verstanden Ihre Frage das erste Mal. Es hört sich so an, als ob Sie tatsächlich den Index erhalten möchten, in dem eine bestimmte Nummer gespeichert ist. Versuchen Sie es in diesem Fall
dict((t[0], i) for i, t in enumerate(thelist))
anstelle einer einfachen alten dict
Bekehrung. Dann d[53]
wäre 2.
Angenommen, die Liste ist lang und die Zahlen wiederholen sich. Verwenden Sie möglicherweise den Typ SortedList aus dem Python-Sortiercontainer-Modul . Der Typ SortedList verwaltet die Tupel automatisch in der Reihenfolge ihrer Nummer und ermöglicht eine schnelle Suche.
Beispielsweise:
from sortedcontainers import SortedList
sl = SortedList([(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")])
# Get the index of 53:
index = sl.bisect((53,))
# With the index, get the tuple:
tup = sl[index]
Dies funktioniert durch eine binäre Suche viel schneller als der Vorschlag zum Listenverständnis. Der Wörterbuchvorschlag ist noch schneller, funktioniert aber nicht, wenn doppelte Zahlen mit unterschiedlichen Zeichenfolgen vorhanden sein könnten.
Wenn es doppelte Zahlen mit unterschiedlichen Zeichenfolgen gibt, müssen Sie einen weiteren Schritt ausführen:
end = sl.bisect((53 + 1,))
results = sl[index:end]
Durch Halbieren für 54 finden wir den Endindex für unser Slice. Dies ist auf langen Listen im Vergleich zur akzeptierten Antwort erheblich schneller.
[k für k, v in l wenn v == ' delicia ']
hier ist l die Liste der Tupel - [(1, "juca"), (22, "james"), (53, "xuxa"), (44, "delicia")]
Und anstatt es in ein Diktat umzuwandeln, verwenden wir das Listenverständnis.
*Key* in Key,Value in list, where value = **delicia**