2011-10-23 15 views
5

uno Supongamos que quiere map sobre una colección, pero sólo recoge los resultados de la función asignada si el mapeado-upon valor cumple con ciertos criterios. Actualmente estoy haciendo esto como por ejemplo:Haskell idioma para el mapa 'selectiva'

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


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

Aunque esto funciona, estoy seguro de que hay una manera más idiomática 'derecho/common/más reconocibles' para hacer esto.

+3

¿El filtro no hace lo que necesita? O tal vez mapMaybe de Data.Maybe? –

+1

@JeffFoster: 'mapMaybe' es la respuesta correcta. Debería publicarlo como respuesta para que podamos votarlo. – Chuck

+0

Sí, Jeff tiene razón. La próxima respuesta tiene mi voto. –

Respuesta

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

mapMaybe del paquete Data.Maybe parece que hace el trabajo. La documentación dice:

La función mapMaybe es una versión del mapa que puede arrojar elementos. En particular, el argumento funcional devuelve algo del tipo Maybe b. Si esto es Nada, no se agrega ningún elemento a la lista de resultados. Si acaba de Just b, entonces b se incluye en la lista de resultados.

0

Hmm. Esto definitivamente parece ser un lugar donde el doblez está bien. ¿Qué hay de:

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

Aquí g es la función que está intentando asignar más de la lista.

no puede pensar en cualquier función que combina de forma nativa mapa y filtro sin plegar.

[EDIT]

Oh, al parecer hay un mapMaybe. Nunca lo usé antes. Estoy corregido. Ja, aprende algo todo el tiempo.

+0

Eek 'foldl'! Acabas de perder tu capacidad de transmitir esta lista. – luqui

+0

Bueno, no hay uno que sea * mejor * entre foldl 'y foldr. Si estuviera procesando una lista grande, no infinita, reduciría el espacio sobrecargado con un foldl '. Sin embargo, si usted mencionó que estaba transmitiendo o trabajando con una lista infinita, foldr sería la única forma en que podría hacerlo. –

+0

No. La sobrecarga de espacio en 'foldl'' es Theta (lista de salida). Spaceoverhead para 'foldr' es O (lista de salida). 'foldl'' hace todo el cálculo antes de regresar,' foldr' hereda la estructura computacional de su usuario. 'foldl'' es un perdedor cuando el tipo de salida no es plano, como en este caso. – luqui

5

Personalmente, haría esto en dos etapas: primero, elimine los valores que no le interesan, luego haga un mapa.

func = map someFunc . filter (>5) 

Esto también se puede expresar muy bien como una lista de comprensión.

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

Si el filtro deseado depende del * valor producido *, puede, por supuesto, invertir el orden: 'filter cond. mapa algunosFunc'. –

Cuestiones relacionadas