map function if a predicate holds
I feel like this should be fairly obvious, or easy, but I just can't get it. What I want to do is apply a function to a开发者_如何学编程 list (using map
) but only if a condition is held. Imagine you only wanted to divide the numbers which were even:
map (`div` 2) (even) [1,2,3,4]
And that would give out [1,1,3,2]
since only the even numbers would have the function applied to them. Obviously this doesn't work, but is there a way to make this work without having to write a separate function that you can give to map
? filter
is almost there, except I also want to keep the elements which the condition doesn't hold for, and just not apply the function to them.
If you don't want to define separate function, then use lambda.
map (\x -> if (even x) then (x `div` 2) else x) [1,2,3,4]
Or instead of a map, list comprehension, bit more readable I think.
[if (even x) then (x `div` 2) else x | x <- [1,2,3,4]]
mapIf p f = map (\x -> if p x then f x else x)
In addition to the answer of PiotrLegnica: Often, it's easier to read if you declare a helper function instead of using a lambda. Consider this:
map helper [1..4] where
helper x | even x = x `div` 2
| otherwise = x
([1..4]
is sugar for [1,2,3,4]
)
If you want to remove all the other elements instead, consider using filter
. filter
removes all elements that don't satisfy the predicate:
filter even [1..4] -> [2,4]
So you can build a pipe of map
and filter than or use list-comprehension instead:
map (`div` 2) $ filter even [1..4]
[x `div` 2 | x <- [1..4], even x]
Choose whatever you like best.
Make your own helper function maker:
ifP pred f x =
if pred x then f x
else x
custom_f = ifP even f
map custom_f [..]
(caveat: I don't have access to a compiler right now. I guess this works OK...)
I like the other, more general solutions, but in your very special case you can get away with
map (\x -> x `div` (2 - x `mod` 2)) [1..4]
Mostly a rip off of existing answers, but according to my biased definition of "readable" (I like guards more than ifs, and where
more than let
):
mapIf p f = map f'
where f' x | p x = f x | otherwise = x
ghci says it probably works
ghci> let mapIf p f = map f' where f' x | p x = f x | otherwise = x
ghci> mapIf even (+1) [1..10]
[1,3,3,5,5,7,7,9,9,11]
精彩评论