我想将一个函数应用于列表中的每个第二个元素:
> mapToEverySecond (*2) [1..10]
[1,4,3,8,5,12,7,16,9,20]
Run Code Online (Sandbox Code Playgroud)
我写了以下函数:
mapToEverySecond :: (a -> a) -> [a] -> [a]
mapToEverySecond f l = map (\(i,x) -> if odd i then f x else x) $ zip [0..] l
Run Code Online (Sandbox Code Playgroud)
这有效,但我想知道是否有更惯用的方法来做这样的事情.
我没有写过很多Haskell,但这是我想到的第一件事:
func :: (a -> a) -> [a] -> [a]
func f [] = []
func f [x] = [x]
func f (x:s:xs) = x:(f s):(func f xs)
Run Code Online (Sandbox Code Playgroud)
这有点过分,因为你不仅需要处理空列表,还需要处理带有一个元素的列表.这也不能很好地扩展(如果你想要每三分之一,或者
人们可以这样做,因为@Landei指出并写道
func :: (a -> a) -> [a] -> [a]
func f (x:s:xs) = x:(f s):(func f xs)
func f xs = xs
Run Code Online (Sandbox Code Playgroud)
为了摆脱丑陋检查的两个[]和[x],但是,恕我直言,这使得它有点困难阅读(至少第一次).
mapToEverySecond = zipWith ($) (cycle [id, (*2)])
Run Code Online (Sandbox Code Playgroud)
是我能想到的最小的,在我看来也看起来很清晰。它也有点随着每n次缩放。
编辑:哦,人们已经在评论中建议了。我不想偷它,但我真的认为这就是答案。
我将如何做到这一点:
mapOnlyOddNumbered f [] = []
mapOnlyOddNumbered f (x:xs) = f x : mapOnlyEvenNumbered f xs
mapOnlyEvenNumbered f [] = []
mapOnlyEvenNumbered f (x:xs) = x : mapOnlyOddNumbered f xs
Run Code Online (Sandbox Code Playgroud)
这是否是"惯用的"是一个意见问题(如果它适合那里我会把它作为评论),但看到许多不同的方法可能是有用的.您的解决方案与我的解决方案或评论中的解决方案一样有效,并且更容易更改为说mapOnlyEvery13nd或mapOnlyPrimeNumbered