2009-10-27 9 views
5

J'ai une fonction foreach qui appelle la fonction spécifiée sur chaque élément qu'elle contient. Je veux obtenir un minimum de ces éléments mais je n'ai aucune idée de la façon d'écrire lambda ou une fonction ou même une classe qui gèrerait ça. Merci pour votre aide. Python, lambda, trouver le minimum


-je utiliser ma fonction foreach comme ceci:

o.foreach(lambda i: i.call()) 

ou

o.foreach(I.call) 

Je n'aime pas faire une liste ou d'autres objets. Je veux itérer à travers et trouver min.

je parviens à écrire une classe qui font le penser, mais il devrait y avoir une meilleure solution que:

class Min:           
    def __init__(self,i):       
     self.i = i        
    def get_min(self):        
     return self.i         
    def set_val(self,o):        
     if o.val < self.i: self.i = o.val 

m = Min(xmin) 
self.foreach(m.set_val)        
xmin = m.get_min() 

Ok, donc je suppose que ma méthode .foreach est une idée non-python. Je devrais faire ma classe itérable parce que toutes vos solutions sont basées sur des listes et tout deviendra plus facile. En C# il n'y aurait pas de problème avec la fonction lambda comme ça, donc je pense que python est aussi puissant.

+3

Pouvez-vous s'il vous plaît poster un exemple de code de ce que vous avez jusqu'à présent? – csl

+1

+1 pour l'étiquette de devoir possible –

Répondre

5

méthode d'écriture foreach est pas très pythonique. Vous devriez mieux en faire un itérateur pour qu'il fonctionne avec les fonctions standard de python comme min.

Au lieu d'écrire quelque chose comme ceci:

def foreach(self, f): 
    for d in self._data: 
     f(d) 

écrire ceci:

def __iter__(self): 
    for d in self._data: 
     yield d 

Maintenant, vous pouvez appeler min comme min(myobj).

+0

Mais comment cela fonctionne quand je casse une itération et la relance? Il commence depuis le début ou à partir du moment où il a été brisé? – qba

+0

Il appelle à nouveau la fonction '__iter__' et renvoie un nouvel itérateur sur l'ensemble des données. –

12

Python a intégré support for finding minimums:

>>> min([1, 2, 3]) 
1 

Si vous avez besoin de traiter la liste avec une fonction première, vous pouvez le faire avec map:

>>> def double(x): 
... return x * 2 
... 
>>> min(map(double, [1, 2, 3])) 
2 

Ou vous pouvez obtenir la fantaisie avec list comprehensions et generator expressions, par exemple:

>>> min(double(x) for x in [1, 2, 3]) 
2 
1

Bon, une chose que vous devez comprendre: lambda crée un objet de fonction pour vous. Mais il en va de même, ordinaire def. Regardez cet exemple:

lst = range(10) 

print filter(lambda x: x % 2 == 0, lst) 

def is_even(x): 
    return x % 2 == 0 

print filter(is_even, lst) 

Ces deux méthodes fonctionnent. Ils produisent le même résultat identique. lambda crée un objet fonction non nommé; def crée un objet fonction nommé. filter() ne se soucie pas de savoir si l'objet fonction a un nom ou non.

Donc, si votre seul problème avec lambda est que vous ne pouvez pas utiliser = dans un lambda, vous pouvez juste faire une fonction à l'aide def. Maintenant, cela dit, je ne suggère pas que vous utilisiez votre méthode .foreach() pour trouver une valeur minimale. Au lieu de cela, faites en sorte que votre objet principal renvoie une liste de valeurs et appelle simplement la fonction Python min().

lst = range(10) 
print min(lst) 

EDIT: Je suis d'accord que la réponse qui a été acceptée est meilleure. Plutôt que de renvoyer une liste de valeurs, il est préférable de définir __iter__() et rendre l'objet itérable.

0

Supposons que vous ayez

>>> seq = range(-4,4) 
>>> def f(x): 
... return x*x-2 

pour la valeur minimale de f

>>> min(f(x) for x in seq) 
-2 

pour la valeur de x au

minimum
>>> min(seq, key=f) 
0 

bien sûr, vous pouvez utiliser lambda trop

>>> min((lambda x:x*x-2)(x) for x in range(-4,4)) 
-2 

mais qui est un peu laid, carte semble mieux ici

>>> min(map(lambda x:x*x-2, seq)) 
-2 

>>> min(seq,key=lambda x:x*x-2) 
0 
1

Je fonction foreach qui appelle la fonction spécifiée sur chaque élément qu'il contient

Il semble, du commentaire Vous avez ensuite posté, que vous avez réinventé la fonction intégrée map.

On dirait que vous cherchez quelque chose comme ceci:

min(map(f, seq)) 

f est la fonction que vous souhaitez faire appel à tous les éléments de la liste.

Comme le montre gnibbler, si vous voulez trouver la valeur x dans la séquence pour laquelle f(x) retourne la valeur la plus basse, vous pouvez utiliser:

min(seq, key=f) 

... sauf si vous voulez trouver tous de les éléments de seq pour lesquels f renvoie la valeur la plus faible. Par exemple, si seq est une liste de dictionnaires,

min(seq, key=len) 

renverra le premier dictionnaire dans la liste avec le nombre d'éléments plus petits, pas tous les dictionnaires qui contiennent ce nombre d'éléments.

Pour obtenir une liste de tous les éléments d'une séquence pour laquelle la fonction f retourne la plus petite valeur, faites ceci:

values = map(f, seq) 
result = [seq[i] for (i, v) in enumerate(values) if v == min(values)] 
+0

Vous devez évaluer le minimum une seule fois avant la compréhension de la liste au lieu de l'évaluer à chaque itération dans la liste de compréhension. En dehors de cela, c'est une bonne réponse. – blubberdiblub

6

Vous ne pouvez pas le faire avec foreach et lambda. Si vous voulez faire cela dans un style fonctionnel sans réellement utiliser min, vous trouverez reduce est assez proche de la fonction que vous essayez de définir.

l = [5,2,6,7,9,8] 
reduce(lambda a,b: a if a < b else b, l[1:], l[0]) 
Questions connexes