tl; dr
Uma expressão geradora é provavelmente a solução mais simples e eficiente para o seu 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
Explicação
Existem várias respostas que fornecem uma solução simples para essa questão com compreensões de lista. Embora essas respostas sejam perfeitamente corretas, elas não são as ideais. Dependendo do seu caso de uso, pode haver benefícios significativos em fazer algumas modificações simples.
O principal problema que vejo ao usar uma compreensão de lista para este caso de uso é que a lista inteira será processada, embora você queira encontrar apenas 1 elemento .
Python fornece uma construção simples que é ideal aqui. É chamada de expressão geradora . Aqui está um exemplo:
# 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)
Podemos esperar que esse método execute basicamente o mesmo que as compreensões de lista em nosso exemplo trivial, mas e se estivermos trabalhando com um conjunto de dados maior? É aí que entra a vantagem de usar o método gerador. Em vez de construir uma nova lista, usaremos sua lista existente como nosso iterável e usaremos next()
para obter o primeiro item de nosso gerador.
Vamos ver como esses métodos funcionam de maneira diferente em alguns conjuntos de dados maiores. Essas são listas grandes, feitas de 10000000 + 1 elementos, com nosso alvo no início (melhor) ou no final (pior). Podemos verificar que ambas as listas terão um desempenho igual usando a seguinte compreensão de lista:
Compreensões de lista
"Pior caso"
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}
"Melhor caso"
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}
Expressões geradoras
Aqui está minha hipótese para geradores: veremos que os geradores terão um desempenho significativamente melhor no melhor caso, mas da mesma forma no pior caso. Esse ganho de desempenho se deve principalmente ao fato de que o gerador é avaliado vagarosamente, o que significa que ele computará apenas o que é necessário para gerar um valor.
Pior caso
# 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}
Melhor caso
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}
O QUE?! O melhor caso destrói as compreensões de lista, mas eu não esperava que nosso pior caso superasse as compreensões de lista a tal ponto. Como é isso? Francamente, eu só poderia especular sem mais pesquisas.
Considere tudo isso com cautela, não executei nenhum perfil robusto aqui, apenas alguns testes básicos. Isso deve ser suficiente para avaliar que uma expressão geradora tem melhor desempenho para esse tipo de pesquisa de lista.
Observe que tudo isso é python básico e integrado. Não precisamos importar nada ou usar qualquer biblioteca.
Eu vi essa técnica pela primeira vez para pesquisa no curso Udacity cs212 com Peter Norvig.