2011-10-23 14 views
5

Supponiamo che si desideri map su una raccolta, ma si raccolgano solo i risultati della funzione mappata se il valore mappato soddisfa determinati criteri. Attualmente sto facendo questo in quanto tale:Idioma di Haskell per la mappa 'selettiva'

func = foldl (\acc x, -> (maybeGrab x):acc) [] 


maybeGrab a 
    | a > 5 = [someFunc a] 
    | otherwise = [] 

Anche se questo funziona, io sono sicuro che ci sia un '/ diritto comune/più riconoscibile' modo più idiomatico per fare questo.

+3

Il filtro non fa ciò che ti serve? O forse mapMaybe da Data.Maybe? –

+1

@JeffFoster: 'mapMaybe' è la risposta corretta. Dovresti postarlo come risposta in modo da poterlo invogliare. – Chuck

+0

Sì, Jeff ha ragione. La prossima risposta ha il mio voto. –

risposta

10
mapMaybe :: (a -> Maybe b) -> [a] -> [b] 

mapMaybe dal pacchetto Data.Maybe sembra che fa il lavoro. La documentazione dice:

La funzione mapMaybe è una versione di mappa che può eliminare elementi. In particolare, l'argomento funzionale restituisce qualcosa di tipo Forse b. Se questo è Nothing, nessun elemento è aggiunto alla lista dei risultati. Se è solo Just b, allora b è incluso nell'elenco dei risultati.

0

Hmm. Questo sicuramente sembra un posto dove una piega va bene. Che dire:

func = foldl (\acc x -> let a = g x in if a > 5 then a:acc else acc) [] 

Qui g è la funzione che si sta tentando di mappare oltre l'elenco.

Non riesco a pensare a nessuna funzione che combina nativamente mappa e filtro senza piegare.

[EDIT]

Oh, a quanto pare c'è un mapMaybe. Mai usato prima. Sono corretto. Ha, impara qualcosa tutto il tempo.

+0

Eek 'foldl'! Hai appena perso la tua capacità di trasmettere questo elenco. – luqui

+0

Bene, non ce n'è uno che sia * migliore * tra foldl 'e foldr. Se stava elaborando una grande lista, non infinita, ridurrebbe lo spazio in testa con una piega '. Se, comunque, hai detto che stava trasmettendo in streaming o lavorando con una lista infinita, foldr sarebbe l'unico modo in cui avrebbe potuto farlo. –

+0

No. L'overhead dello spazio in 'foldl'' è Theta (lista di output). Spaceoverhead per 'foldr' è O (lista di output). 'foldl'' fa tutto il calcolo prima di tornare,' foldr' eredita la struttura computazionale del suo utente. 'foldl'' è un perdente quando il tipo di output non è piatto, come in questo caso. – luqui

5

Personalmente, lo farei in due fasi: in primo luogo, eliminare i valori che non ti interessano, quindi mappare.

func = map someFunc . filter (>5) 

Questo può anche essere espresso come una comprensione di lista.

func xs = [someFunc x | x <- xs, x > 5] 
+0

Se il filtro desiderato dipende dal * valore prodotto *, è possibile, naturalmente, invertire l'ordine: 'filtro cond. mappare someFunc'. –

Problemi correlati