如何从列表中选择每个第n个元素

sha*_*unc 5 haskell

可能重复:
如何在Haskell中获取无限列表的每个第N个元素?

简单的任务 - 我们有一个列表,并希望只留下该列表中的每个第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)


Dan*_*ner 8

很多方法刮胡子!这是另一个:

import Data.List.Split -- from the "split" package on Hackage
dr n = map head . chunk n
Run Code Online (Sandbox Code Playgroud)