Je veux une manière idiomatique de trouver le premier élément d'une liste qui correspond à un prédicat.
Le code actuel est assez moche:
[x for x in seq if predicate(x)][0]
J'ai pensé à le changer en:
from itertools import dropwhile
dropwhile(lambda x: not predicate(x), seq).next()
Mais il doit y avoir quelque chose de plus élégant ... Et ce serait bien s'il renvoie une None
valeur plutôt que de lever une exception si aucune correspondance n'est trouvée.
Je sais que je pourrais simplement définir une fonction comme:
def get_first(predicate, seq):
for i in seq:
if predicate(i): return i
return None
Mais il est assez insipide de commencer à remplir le code avec des fonctions utilitaires comme celle-ci (et les gens ne remarqueront probablement pas qu'elles sont déjà là, donc elles ont tendance à se répéter au fil du temps) s'il y a des inserts intégrés qui fournissent déjà la même chose.
Réponses:
Pour rechercher le premier élément d'une séquence
seq
qui correspond à unpredicate
:Ou (
itertools.ifilter
sur Python 2) :Il augmente
StopIteration
s'il n'y en a pas.Pour retourner
None
s'il n'y a pas un tel élément:Ou:
la source
next
qui est utilisé au lieu de lever l'exception.next()
est disponible depuis Python 2.6 Vous pouvez lire la page Quoi de neuf pour vous familiariser rapidement avec les nouvelles fonctionnalités.seq.find(&method(:predicate))
ou même plus concis par exemple les méthodes par exemple:[1,1,4].find(&:even?)
ifilter
a été renomméfilter
en Python 3.Vous pouvez utiliser une expression de générateur avec une valeur par défaut, puis
next
:Bien que pour ce one-liner, vous devez utiliser Python> = 2.6.
Cet article plutôt populaire traite plus en détail de ce problème: Fonction de recherche dans la liste Python la plus propre? .
la source
Je ne pense pas qu'il y ait quelque chose qui cloche dans les solutions que vous avez proposées dans votre question.
Dans mon propre code, je l'implémenterais comme ceci:
La syntaxe avec
()
crée un générateur, ce qui est plus efficace que de générer toute la liste en même temps avec[]
.la source
[]
vous pourriez rencontrer des problèmes si l'itérateur ne se termine jamais ou si ses éléments sont difficiles à créer, plus il'generator' object has no attribute 'next'
sur Python 3.La réponse de JF Sebastian est la plus élégante mais nécessite python 2.6 comme l'a souligné fortran.
Pour la version Python <2.6, voici le meilleur que je puisse proposer:
Alternativement, si vous aviez besoin d'une liste plus tard (la liste gère la StopIteration), ou si vous aviez besoin de plus que la première mais pas de la totalité, vous pouvez le faire avec islice:
MISE À JOUR: Bien que j'utilise personnellement une fonction prédéfinie appelée first () qui intercepte un StopIteration et renvoie None, voici une amélioration possible par rapport à l'exemple ci-dessus: évitez d'utiliser filter / ifilter:
la source