2011-09-29 163 views
5

可能重复:
How to get every Nth element of an infinite list in Haskell?如何从列表中选择每第n个元素

简单的任务 - 我们有一个列表,并希望只留下每个第n个元素在该列表。 哈斯克尔最习惯的方式是什么?

了我的头顶部是这样的:

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

,但我有我的过分复杂问题的一种强烈的感觉。

+2

小艾习惯给我。 –

+2

不认为你会得到这个更便宜 - 看起来很好。唯一的一点是,这不符合你的描述,因为'dr k [1 ..]'不会产生你的问题序列。 – Carsten

回答

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采用迭代,从而不会终止(也许这是确定的无限列表,但可能不是一个很好的整体解决方案):

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

托马斯,非常感谢。了解你可以执行相对简单的任务的所有方式非常重要,并且你刚刚给了我一些新的想法。 – shabunc

13

我的变种是:

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

快速和懒惰打得很好。

+0

这一个很好! – shabunc

+1

是的,这是非常好的。我不想讨论懒惰(并且诚实地不考虑增加一名空档警卫),但是这是我第一个破例的好选择。 –

8

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

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

块非常相似,实际上' - | split = chunk :: Int - > [a] - > [[a]] chunk _ [] = [[]] chunk n xs = y1:chunk n y2 其中 (y1,y2)= splitAt n xs' – shabunc

+0

@shabunc你打赌!代码重用是游戏的名称。 –

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

该解决方案不适用于无限列表(因为“长度列表”);泄漏空间(它强制列表脊柱,但不会释放列表的开始,直到它终止);从列表中获取元素是低效的('!!'是O(n);这是[Schlemiel the Painter's algorithm](http://en.wikipedia.org/wiki/Schlemiel_the_Painter%27s_algorithm));太复杂了。 – dave4420

相关问题