2010-03-03 5 views
6

J'ai besoin d'une fonction capable d'itérer sur la collection, d'appeler une fonction fournie avec un élément de la collection en tant que paramètre et de renvoyer le paramètre ou son index lors de la réception "Vrai" de la fonction fournie.Python - "trouver" fonctionnel?

Il est somethong comme ceci:

def find(f, seq, index_only=True, item_only=False): 
    """Return first item in sequence where f(item) == True.""" 
    index = 0 
    for item in seq: 
     if f(item): 
      if index_only: 
       return index 
      if item_only: 
       return item 
      return index, item 
     index+= 1 
    raise KeyError 

Je me demande s'il y a quelque chose comme ça dans le jeu d'outils python Standart?

+2

L'extrait de l'OP est le moyen le plus direct (mais un peu plus long) d'exprimer l'exigence; il pourrait bien être la façon prescrite, selon la situation. A partir des réponses, cependant, vient un aperçu très utile: 'concernant les boucles, en cas de doute, consulter/considérer des outils '. – mjv

Répondre

2

Vous pouvez utiliser itertools.dropwhile pour ignorer les éléments pour lesquels la fonction fournie renvoie False, puis prenez le premier élément du reste (le cas échéant). Si vous avez besoin de l'index plutôt que de l'élément, intégrez enumerate dans la section Recettes de itertools docs.

Pour inverser les valeurs de vérité renvoyées par la fonction fournie, utilisez un lambda (lambda x: not pred (x), où pred est la fonction fournie) ou une enveloppe nommée:

def negate(f): 
    def wrapped(x): 
     return not f(x) 
    return wrapped 

Exemple:

def odd(x): return x % 2 == 1 
itertools.dropwhile(negate(odd), [2,4,1]).next() 
# => 1 

Cette volonté lancer StopIteration si aucun élément correspondant n'est trouvé; enveloppez-le dans une de vos fonctions pour lancer une exception de votre choix à la place.

+0

:(Je pense que la question d'OP est elle-même la réponse, cela peut être un peu plus pour une simple itération –

+0

Je suis d'accord avec Anurag, mais si 'itertools' était utilisé, je pense que' ifilter' serait plus simple. (impair, [2,4,1]). next() ' – tgray

+0

Je suis enclin à me mettre d'accord sur le' ifilter. 'En outre, l'extrait de l'OP résout bien le problème de base, tout en se demandant ce qu'il y a dans le standard lib pour aider à éviter d'écrire du code pour des trucs comme celui-ci semble assez raisonnable.Je dirais que le commentaire de mjv sur la question résume parfaitement la leçon importante ici. –

3

Je ne pense pas qu'il existe une telle fonction avec une telle sémantique exacte, et de toute façon votre fonction est courte, assez bonne et vous pouvez facilement l'améliorer pour une utilisation ultérieure, alors utilisez-la.

parce que simple est meilleur que complexe.