没有步伐功能

时间:2013-01-04 15:09:16

标签: list haskell

我最近需要 stride 一个列表,以便只查看一些元素。它有点像过滤器功能,但并不是那么简单。但首先,这是一个跨越的步伐。

跨越列表 - 或任何可遍历的类型 - 与折叠它相同,但丢弃一些经常遇到的元素(关于步幅值)。我们选择一个元素,然后选择下一个值将是下一个 th 一个。例如,如果我们跨步一个步幅值设置为0的列表,我们实际上会使列表保持不变。如果我们将1列入一个列表,我们将得到一个元素:

stride 0 [1..10] == [1..10]
stride 1 [1..10] == [1,3,5,7,9]
stride 2 [1..10] == [1,4,7,10]

我看了Data.List,我没有找到stride列表。这就是为什么我写了一个功能来跨越我 - 和你的! - 东西:

import Data.DList

-- for Data.List
stride :: (Num a, Eq a) => a -> [b] -> [b]
stride s = toList . snd . foldl (\(sa,xa) x -> if sa == s then (0,xa `snoc` x) else (sa+1,xa)) (s,fromList [])

您可以像上面一样使用它。 有可能建议它成为Data.List模块的一部分吗?我认为它可以提供很多帮助。

3 个答案:

答案 0 :(得分:8)

一个更简单的实现,也适用于无限列表,效率更高

stride :: Int -> [a] -> [a]
stride s = go
  where
    go (x:xs) = x : go (drop s xs)
    go _      = []

如果您希望将其用于除Int之外的其他类型,请将其设为

import Data.List

stride :: Integral i => i -> [a] -> [a]
stride s = go
  where
    go (x:xs) = x : go (genericDrop s xs)
    go _      = []

为非整数类型做这件事没有意义IMO。

  

是否可以建议将其作为Data.List模块的一部分?

是的,可以在libraries@haskell.org邮件列表上提出建议。

但是,我不认为它会被接受。实用性太小,无法将其添加到base包中。它会更好地添加到另一个包中。也许将其包括在split中是最好的。

答案 1 :(得分:3)

此功能并不能完全符合您的要求,但您可以将stride功能基于此功能:

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

现在你的步幅可能看起来像这样:

stride :: Int -> [a] -> [a]
stride n = map head . chunksOf (n + 1)

使用head就行了,因为takeWhile (not . null)确保子列表永远不会为空。

答案 2 :(得分:0)

或者使用lens包,您可以:

>stridingOf l n = (elementsOf l ((==0) . (flip mod (n + 1))))
>striding = stridingOf traverse
>stride n = toListOf striding

>stride 1 [1..10]
[1,3,5,7,9]

编写stridingOf而不仅仅是striding的一些额外工作允许在text和byteStrings上使用lens包时更难以重写。

>import Data.Text
>import Data.Text.Lens

>testText = pack "This is a test"
>toListOf (stridingOf text 1) testText
"Ti sats"

#lens