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

Haskell 如何从列表中选择第n个元素,haskell,Haskell,可能重复: 简单任务-我们有一个列表,只想保留该列表中的第n个元素。 在haskell中最惯用的方法是什么 在我的脑海里,它是这样的: dr n [] = [] dr n (x : xs) = x : (dr n $ drop n xs) 但是我有一种强烈的感觉,我把问题复杂化了。您的解决方案很好,但这里有三个使用Haskell的基本库函数的其他解决方案 dr1 m = concatMap (take 1) . iterate (drop m) 当然,这永远不会终止(因为iterate永远

可能重复:

简单任务-我们有一个列表,只想保留该列表中的第n个元素。 在haskell中最惯用的方法是什么

在我的脑海里,它是这样的:

dr n [] = []
dr n (x : xs) = x : (dr n $ drop n xs)

但是我有一种强烈的感觉,我把问题复杂化了。

您的解决方案很好,但这里有三个使用Haskell的基本库函数的其他解决方案

dr1 m = concatMap (take 1) . iterate (drop m)
当然,这永远不会终止(因为
iterate
永远不会终止)。因此,也许更好的解决方案是使用
unfover

{-# LANGUAGE TupleSections #-}
import Data.Maybe
dr2 m = unfoldr ((\x-> fmap (,drop m x) (listToMaybe x)))
如果您不知道GHC扩展和诸如函子之类的概念,那么传递给展开的函数可能会变得有点难看,这里再次提供了一个解决方案,没有花哨的步法(未经测试):

如果你不喜欢展开,那么考虑一个zip和一个过滤器:

dr3 m = map snd . filter ((== 1) . fst) . zip (cycle [1..m])
回顾

了解所有这些解决方案都略有不同。了解为什么会让你成为一名更好的Haskell程序员
dr1
使用迭代,因此永远不会终止(也许这对于无限列表是可以的,但可能不是一个好的总体解决方案):

dr2
解决方案将通过跳过展开中的值来显示每个
m
th值。展开在单个元组中传递用于下一次展开的值和当前展开的结果

> dr2 99 [1..400]
[1,100,199,298,397]
dr3
解决方案略长,但初学者可能更容易理解。首先,用
[1..n,1..n,1..n…]的循环标记列表中的每个元素。其次,只选择带有
1
标记的数字,有效地跳过元素的
n-1
。第三,移除标记

> dr3 99 [1..400]
[1,100,199,298,397]
我的变体是:

each :: Int -> [a] -> [a]
each n = map head . takeWhile (not . null) . iterate (drop n)

速度快,很好地解决了懒惰问题。

剃牦牛的方法很多!还有一点:

import Data.List.Split -- from the "split" package on Hackage
dr n = map head . chunk n
试试这个:

getEach :: Int -> [a] -> [a]
getEach _ [] = []
getEach n list
 | n < 1     = []
 | otherwise = foldr (\i acc -> list !! (i - 1):acc) [] [n, (2 * n)..(length list)]

对我来说,这看起来很地道。别以为你会买到更便宜的——对我来说很好。唯一的一点是,这不符合你的描述,因为
k[1..]
没有给出你的问题顺序。托马斯,非常感谢。知道你能完成相对简单的任务的所有方法是非常重要的,你刚刚给了我一些新的想法。是的,这很好。我不想讨论懒惰(并且老实说,没有考虑添加一个空的警卫),但是这是一个很好的替代方法,我的破译第一个例子。实际上,块是非常类似的,实际上是代码> >分裂成规则的块::INT--> [A]-[[A][C][][[]]块N xs= y1:块ny2(y1,y2)。=splitAt n xs
@shabunc当然!代码重用是游戏的名称。
import Data.List.Split -- from the "split" package on Hackage
dr n = map head . chunk n
getEach :: Int -> [a] -> [a]
getEach _ [] = []
getEach n list
 | n < 1     = []
 | otherwise = foldr (\i acc -> list !! (i - 1):acc) [] [n, (2 * n)..(length list)]
*Main> getEach 2 [1..10]
[10,8,6,4,2]