2009-10-27 17 views
5

Mam funkcję foreach, która wywołuje określoną funkcję dla każdego elementu, który zawiera. Chcę uzyskać minimum z tych elementów, ale nie mam pojęcia, jak napisać lambdę lub funkcję, a nawet klasy, która to poradzi. Dzięki za każdą pomoc. Python, lambda, znajdź minimum


używam funkcji foreach tak:

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

lub

o.foreach(I.call) 

nie podoba mi się zrobić list lub innych przedmiotów. Chcę iterować przez to i znaleźć min.

udaje mi się napisać klasę, że zrobić to myśleć, ale nie powinno być jakieś lepsze rozwiązanie niż:

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, więc przypuszczam, że moja metoda .foreach jest non-python pomysł. Powinienem uczynić swoją klasę iterowalną, ponieważ wszystkie twoje rozwiązania oparte są na listach, a wtedy wszystko stanie się łatwiejsze.

W języku C# nie byłoby problemu z taką funkcją lambda, więc myślę, że ten pyton jest również tak potężny.

+3

Czy możesz podać przykładowy kod tego, co masz do tej pory? – csl

+1

+1 dla możliwego tagu zadania domowego –

Odpowiedz

5

Pisanie metody foreach nie jest bardzo pythonic. Powinieneś lepiej zrobić iterator, aby działał ze standardowymi funkcjami Pythona, takimi jak min.

Zamiast pisać coś takiego:

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

zapisu to:

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

Teraz można zadzwonić min jak min(myobj).

+0

Ale jak to działa, gdy przerywam iterację i uruchamiam ją ponownie? Zaczyna się od początku lub od momentu, w którym zostało zerwane? – qba

+0

Powoduje ponowne wywołanie funkcji '__iter__' i zwraca nowy iterator w obrębie wszystkich danych. –

1

Okay, jedną rzecz musisz zrozumieć: lambda tworzy dla ciebie obiekt funkcji. Ale tak samo robi zwykły, zwykły def. Spójrz na ten przykład:

lst = range(10) 

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

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

print filter(is_even, lst) 

Obie te prace. Dają taki sam identyczny wynik. lambda tworzy nienazwany obiekt funkcji; def tworzy nazwany obiekt funkcji. filter() nie obchodzi, czy obiekt funkcji ma nazwę, czy nie.

Dlatego, jeśli tylko problem z lambda jest to, że nie można używać = w lambda, można po prostu zrobić funkcję używając def.

Powiedziałem, że nie sugeruję stosowania metody .foreach() w celu znalezienia wartości minimalnej. Zamiast tego spraw, aby główny obiekt zwrócił listę wartości i po prostu wywołaj funkcję Python min().

lst = range(10) 
print min(lst) 

EDYCJA: Zgadzam się, że odpowiedź, która została zaakceptowana, jest lepsza. Zamiast zwracania listy wartości lepiej jest zdefiniować __iter__() i uczynić obiekt iterowalnym.

0

Załóżmy, że masz

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

minimalnej wartości f

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

dla wartości X w minimalnej

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

oczywiście można użyć lambda zbyt

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

ale to trochę brzydki, mapa wygląda lepiej tutaj

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

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

Mam funkcji foreach, która wywołuje określoną funkcję na każdym elemencie, który zawiera ona

się wydaje, z komentarzem następnie opublikowałeś, że ponownie wynalazłeś wbudowaną funkcję map.

Brzmi jak szukasz czegoś takiego:

min(map(f, seq)) 

gdzie f jest funkcja, którą chcesz zadzwonić na każdej pozycji na liście.

Jak gnibbler pokazów, jeśli chcesz znaleźć wartość x w sekwencji, dla których f(x) zwraca najmniejszą wartość, można użyć:

min(seq, key=f) 

... chyba, że ​​chcesz znaleźć wszystkie z pozycje w seq, dla których f zwraca najniższą wartość. Na przykład, jeśli seq jest lista słowników,

min(seq, key=len) 

zwróci pierwszy słownik w liście z najmniejszej liczby elementów, nie wszystkie słowników, które zawierają tę liczbę elementów.

Aby uzyskać listę wszystkich elementów w sekwencji, dla których funkcja f zwraca najmniejszą wartość, to zrobić:

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

Powinieneś ocenić minimum tylko raz przed zrozumieniem listy, zamiast oceniać ją w kółko dla każdej iteracji w zrozumieniu listy. Poza tym to dobra odpowiedź. – blubberdiblub

6

Nie można tego zrobić z foreach i lambda. Jeśli chcesz to zrobić w stylu funkcjonalnym, bez korzystania z min, znajdziesz reduce w pobliżu funkcji, którą próbujesz zdefiniować.

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