tl; dr
Une 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 liste. Bien que ces réponses soient parfaitement correctes, elles ne sont pas optimales. Selon votre cas d'utilisation, il peut y avoir des avantages importants à 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 liste entière sera traitée, bien que vous ne souhaitiez trouver qu'un élément .
Python fournit une construction simple qui est idéale ici. Cela s'appelle l' expression du 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)
Nous pouvons nous attendre à ce que cette méthode fonctionne essentiellement de la même manière que les compréhensions de liste dans notre exemple trivial, mais que se passe-t-il si nous travaillons avec un ensemble de données plus grand? 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 notre itérable, et utiliseronsnext()
pour obtenir le premier élément de notre générateur.
Voyons comment ces méthodes fonctionnent différemment sur certains ensembles de données plus volumineux. Ce sont de grandes listes, faites de 10000000 + 1 éléments, avec notre cible au début (meilleur) ou à la fin (pire). Nous pouvons vérifier que ces deux listes fonctionneront de la même manière en utilisant la compréhension de liste suivante:
Compréhensions de listes
"Pire 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 de générateur
Voici mon hypothèse pour les générateurs: nous verrons que les générateurs fonctionneront nettement mieux dans le meilleur des cas, mais de même dans le pire des cas. Ce gain de performance est principalement dû au fait que le générateur est évalué paresseusement, ce qui signifie qu'il ne calculera que ce qui est nécessaire pour produire une valeur.
Pire 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}
QUELLE?! Le meilleur cas emporte les compréhensions de liste, mais je ne m'attendais pas à ce que notre pire cas surpasse les compréhensions de liste à un tel point. Comment c'est? Franchement, je ne pouvais que spéculer sans autre recherche.
Prenez tout cela avec un grain de sel, je n'ai pas exécuté de profilage robuste ici, juste des tests très basiques. Cela devrait être suffisant pour apprécier qu'une expression de générateur est plus performante pour ce type de recherche de liste.
Notez que tout cela est du python intégré de base. Nous n'avons pas besoin d'importer quoi que ce soit ou d'utiliser des bibliothèques.
J'ai vu cette technique pour la première fois dans le cours Udacity cs212 avec Peter Norvig.