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

时间:2011-09-29 15:35:00

标签: haskell

  

可能重复:
  How to get every Nth element of an infinite list in Haskell?

简单的任务 - 我们有一个列表,并希望只留下该列表中的每个第n个元素。 在haskell中最常用的方法是什么?

脱离我的头顶,它是这样的:

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

但我有一种强烈的感觉,我对这个问题过于复杂。

4 个答案:

答案 0 :(得分:14)

我的变体是:

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

速度快,而且懒惰也很好。

答案 1 :(得分:10)

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

dr1 m = concatMap (take 1) . iterate (drop m)

粗略地说,这永远不会终止(因为iterate永远不会终止)。因此,或许更好的解决方案是使用unfoldr

{-# LANGUAGE TupleSections #-}
import Data.Maybe
dr2 m = unfoldr ((\x-> fmap (,drop m x) (listToMaybe x)))

如果您不了解GHC扩展和诸如仿函数之类的概念,那么您传递给展开的函数会变得有点难看,这里的解决方案再次没有花哨的脚步(未经测试):

dr2 m = unfoldr ((\x -> case listToMaybe x of
                         Nothing -> Nothing
                         Just i  -> Just (i,drop m x)))

如果您不喜欢展开,请考虑使用拉链和滤镜:

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

查看

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

> dr1 99 [1..400]
[1,100,199,298,397^CInterrupted.

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

> 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]

答案 2 :(得分:8)

有很多方法可以剃掉这只牦牛!这是另一个:

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

答案 3 :(得分:0)

试试这个:

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

然后在GHC:

*Main> getEach 2 [1..10]
[10,8,6,4,2]