2009-10-27 15 views
5

Ho una funzione foreach che chiama la funzione specificata su ogni elemento che contiene. Voglio ottenere il minimo da questi elementi, ma non ho idea di come scrivere lambda o funzione o anche una classe che possa gestirlo. Grazie per l'aiuto. Python, lambda, trova minimo


posso utilizzare la mia funzione foreach in questo modo:

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

o

o.foreach(I.call) 

non mi piace fare un elenchi o altri oggetti. Voglio iterare attraverso di esso e trovare min.

riesco a scrivere una classe che fanno il pensare, ma ci dovrebbe essere una soluzione migliore di quella:

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, quindi suppongo che il mio metodo .foreach è un'idea non-python. Dovrei fare la mia lezione ripetibile perché tutte le tue soluzioni sono basate su elenchi e quindi tutto diventerà più facile.

In C# non ci sarebbe alcun problema con la funzione lambda del genere, quindi penso che anche questo python sia così potente.

+3

Puoi per favore postare qualche esempio di codice di quello che hai ottenuto finora? – csl

+1

+1 per il tag di possibili compiti –

risposta

5

metodo di scrittura foreach non è molto divinatorio. Dovresti renderlo un iteratore in modo che funzioni con le funzioni standard di Python come min.

Invece di scrivere qualcosa di simile:

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

scrivere questo:

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

Ora è possibile chiamare min come min(myobj).

+0

Ma come funziona quando interrompo un iterazione e lo avvio di nuovo? Inizia dall'inizio o dal momento in cui è stato rotto? – qba

+0

Chiama di nuovo la funzione '__iter__' e restituisce un nuovo iteratore su tutti i dati. –

12

Python è dotato di support for finding minimums:

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

Se è necessario elaborare l'elenco con una funzione di prima, è possibile farlo con map:

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

Oppure si può ottenere fantasia con list comprehensions e generator expressions, ad esempio:

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

Ok, una cosa che devi capire: lambda crea un oggetto funzione per te. Ma altrettanto semplice, ordinario def. Guarda questo esempio:

lst = range(10) 

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

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

print filter(is_even, lst) 

Entrambi questi lavori. Producono lo stesso identico risultato. lambda crea un oggetto funzione non denominato; def crea un oggetto funzione con nome. filter() non interessa se l'oggetto funzione ha un nome o meno.

Quindi, se il vostro unico problema con lambda è che non è possibile utilizzare in un =lambda, si può solo fare una funzione usando def.

Ora, ciò detto, non suggerisco di utilizzare il metodo .foreach() per trovare un valore minimo. Invece, fai in modo che l'oggetto principale restituisca un elenco di valori e chiami semplicemente la funzione Python min().

lst = range(10) 
print min(lst) 

MODIFICA: Sono d'accordo che la risposta che è stata accettata è migliore. Anziché restituire un elenco di valori, è meglio definire __iter__() e rendere l'oggetto iterabile.

0

Supponiamo di avere

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

per il valore minimo di f

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

per il valore di x al minimo

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

naturalmente è possibile utilizzare lambda troppo

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

ma che è un po 'brutto, mappa sembra meglio qui

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

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

ho funzione foreach che chiama la funzione specificata su ogni elemento che contiene

Sembra, dal commento in seguito, ha pubblicato di aver reinventato la funzione integrata map.

suona come siete alla ricerca di qualcosa di simile:

min(map(f, seq)) 

dove f è la funzione che si desidera chiamare su ogni elemento della lista.

Come dimostra gnibbler, se si vuole trovare il valore x nella sequenza per la quale f(x) restituisce il valore più basso, è possibile utilizzare:

min(seq, key=f) 

... a meno che non si desidera trovare tutte di gli articoli in seq per i quali f restituisce il valore più basso. Per esempio, se seq è un elenco di dizionari,

min(seq, key=len) 

tornerà il primo dizionario nella lista con il minor numero di elementi, non tutti i dizionari che contengono quel numero di elementi.

per ottenere un elenco di tutti gli elementi in una sequenza per la quale la funzione f restituisce il valore più piccolo, fare questo:

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

È necessario valutare il minimo una sola volta prima della comprensione dell'elenco invece di valutarlo ripetutamente durante l'intera comprensione della lista. A parte questo, è una bella risposta. – blubberdiblub

6

Non si può fare questo con foreach e un lambda. Se vuoi farlo in uno stile funzionale senza utilizzare effettivamente lo min, troverai che reduce è abbastanza vicino alla funzione che stavi tentando di definire.

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