Tl;dr
A expression de générateur est probablement la solution la plus performante et la plus simple à votre problème :
l = [(1,"juca"),(22,"james"),(53,"xuxa"),(44,"delicia")]
result = next((i for i, v in enumerate(l) if v[0] == 53), None)
# 2
Explication
Il existe plusieurs réponses qui fournissent une solution simple à cette question avec des compréhensions de listes. Bien que ces réponses soient parfaitement correctes, elles ne sont pas optimales. En fonction de votre cas d'utilisation, il peut y avoir des avantages significatifs à apporter quelques modifications simples.
Le principal problème que je vois avec l'utilisation d'une compréhension de liste pour ce cas d'utilisation est que la fonction liste complète sera traité, même si vous voulez seulement trouver 1 élément .
Python fournit une construction simple qui est idéale ici. Elle s'appelle le expression de générateur . Voici un exemple :
# 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)
On peut s'attendre à ce que cette méthode fonctionne de la même manière que les compréhensions de listes dans notre exemple trivial, mais que se passe-t-il si nous travaillons avec un ensemble de données plus important ? C'est là que l'avantage d'utiliser la méthode du générateur entre en jeu. Plutôt que de construire une nouvelle liste, nous utiliserons votre liste existante comme itérable, et nous utiliserons la méthode du générateur. next()
pour obtenir le premier élément de notre générateur.
Voyons comment ces méthodes se comportent différemment sur certains ensembles de données plus importants. Il s'agit de grandes listes, composées de 10000000 + 1 éléments, avec notre cible au début (le meilleur) ou à la fin (le pire). Nous pouvons vérifier que ces deux listes ont les mêmes performances en utilisant la compréhension de liste suivante :
Compréhensions de listes
"Le pire des cas"
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}
"Meilleur cas"
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}
Expressions du générateur
Voici mon hypothèse pour les générateurs : nous verrons que les générateurs auront des performances nettement meilleures dans le meilleur des cas, mais similaires dans le pire des cas. Ce gain de performance est principalement dû au fait que le générateur est évalué de manière paresseuse, c'est-à-dire qu'il ne calcule que ce qui est nécessaire pour obtenir une valeur.
Le pire des cas
# 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}
Meilleur cas
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}
QUOI ? ! Le meilleur cas s'envole mais je ne m'attendais pas à ce que notre pire cas surpasse à ce point les comprehensions de listes. Comment cela se fait-il ? Franchement, je ne peux que spéculer sans faire de recherches supplémentaires.
Prenez tout cela avec un grain de sel, je n'ai pas effectué de profilage robuste ici, juste quelques tests très basiques. Cela devrait suffire pour comprendre qu'une expression de générateur est plus performante pour ce type de recherche de liste.
Notez que tout ceci est du python de base, intégré. Nous n'avons pas besoin d'importer quoi que ce soit ou d'utiliser des bibliothèques.
J'ai vu pour la première fois cette technique de recherche dans le Udacity cs212 cours avec Peter Norvig.