简单的任务 - 我们有一个列表,并希望只留下该列表中的每个第n个元素.在haskell中最常用的方法是什么?
脱离我的头顶是这样的:
dr n [] = []
dr n (x : xs) = x : (dr n $ drop n xs)
Run Code Online (Sandbox Code Playgroud)
但我有一种强烈的感觉,我对这个问题过于复杂.
小智 14
我的变体是:
each :: Int -> [a] -> [a]
each n = map head . takeWhile (not . null) . iterate (drop n)
Run Code Online (Sandbox Code Playgroud)
快速,懒惰,玩得很好.
Tho*_*son 10
您的解决方案很好,但是这里有三个使用Haskell基本库函数的其他解决方案.
dr1 m = concatMap (take 1) . iterate (drop m)
Run Code Online (Sandbox Code Playgroud)
粗略的,这将永远不会终止(因为iterate永远不会终止).所以也许更好的解决方案是使用unfoldr:
{-# LANGUAGE TupleSections #-}
import Data.Maybe
dr2 m = unfoldr ((\x-> fmap (,drop m x) (listToMaybe x)))
Run Code Online (Sandbox Code Playgroud)
如果您不了解GHC扩展和诸如仿函数之类的概念,那么您传递给展开的函数会变得有点难看,这里的解决方案再次没有花哨的脚步(未经测试):
dr2 m = unfoldr ((\x -> case listToMaybe x of
Nothing -> Nothing
Just i -> Just (i,drop m x)))
Run Code Online (Sandbox Code Playgroud)
如果您不喜欢展开,请考虑使用拉链和过滤器:
dr3 m = map snd . filter ((== 1) . fst) . zip (cycle [1..m])
Run Code Online (Sandbox Code Playgroud)
评论
了解所有这些解决方案略有不同.学习为什么会让你成为一个更好的Haskell程序员. dr1使用迭代,因此永远不会终止(也许这对于无限列表是可以的,但可能不是一个好的整体解决方案):
> dr1 99 [1..400]
[1,100,199,298,397^CInterrupted.
Run Code Online (Sandbox Code Playgroud)
该dr2解决方案将显示每一个m通过在展开跳过值个值.展开传递用于下一次展开的值和当前展开的单个元组的结果.
> dr2 99 [1..400]
[1,100,199,298,397]
Run Code Online (Sandbox Code Playgroud)
该dr3解决方案是稍长,但可能更容易为初学者理解.首先,用循环标记列表中的每个元素[1..n, 1..n, 1..n ...].其次,您只选择标记为a的数字1,有效地跳过n-1元素.第三,删除标签.
> dr3 99 [1..400]
[1,100,199,298,397]
Run Code Online (Sandbox Code Playgroud)
很多方法刮胡子!这是另一个:
import Data.List.Split -- from the "split" package on Hackage
dr n = map head . chunk n
Run Code Online (Sandbox Code Playgroud)