tl; dr
Un generatore di espressione è probabilmente la soluzione più performante e semplice al tuo problema:
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
result = next((i for i, v in enumerate(l) if v[0] == 53), None)
# 2
Spiegazione
Ci sono diverse risposte che forniscono una semplice soluzione a questa domanda con la comprensione degli elenchi. Sebbene queste risposte siano perfettamente corrette, non sono ottimali. A seconda del tuo caso d'uso, potrebbero esserci vantaggi significativi apportando alcune semplici modifiche.
Il problema principale che vedo con l'utilizzo di una comprensione dell'elenco per questo caso d'uso è che l' intero elenco verrà elaborato, sebbene tu voglia trovare solo 1 elemento .
Python fornisce un semplice costrutto che è l'ideale qui. Si chiama espressione del generatore . Ecco un esempio:
# 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)
Possiamo aspettarci che questo metodo abbia fondamentalmente lo stesso risultato delle comprensioni di lista nel nostro banale esempio, ma cosa succede se stiamo lavorando con un set di dati più grande? È qui che entra in gioco il vantaggio di utilizzare il metodo del generatore. Piuttosto che costruire un nuovo elenco, useremo l'elenco esistente come nostro iterabile e useremo next()per ottenere il primo elemento dal nostro generatore.
Vediamo come questi metodi si comportano in modo diverso su alcuni set di dati più grandi. Si tratta di elenchi di grandi dimensioni, composti da 10000000 + 1 elementi, con il nostro obiettivo all'inizio (migliore) o alla fine (peggiore). Possiamo verificare che entrambi questi elenchi funzioneranno allo stesso modo utilizzando la seguente comprensione dell'elenco:
Elenca le comprensioni
"Caso peggiore"
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}
"Caso migliore"
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}
Espressioni del generatore
Ecco la mia ipotesi per i generatori: vedremo che i generatori avranno prestazioni significativamente migliori nel migliore dei casi, ma allo stesso modo nel peggiore dei casi. Questo aumento delle prestazioni è dovuto principalmente al fatto che il generatore viene valutato pigramente, il che significa che calcolerà solo ciò che è necessario per produrre un valore.
Nel peggiore dei casi
# 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}
Caso migliore
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}
CHE COSA?! Il caso migliore spazza via le comprensioni dell'elenco, ma non mi aspettavo che il nostro caso peggiore superasse a tal punto le comprensioni dell'elenco. Com'è? Francamente, potevo solo speculare senza ulteriori ricerche.
Prendi tutto questo con le pinze, non ho eseguito alcun profilo robusto qui, solo alcuni test di base. Ciò dovrebbe essere sufficiente per comprendere che un'espressione del generatore è più performante per questo tipo di ricerca nell'elenco.
Nota che questo è tutto Python di base integrato. Non è necessario importare nulla o utilizzare alcuna libreria.
Ho visto per la prima volta questa tecnica per la ricerca nel corso Udacity cs212 con Peter Norvig.