将字符串转换为描述序列的子字符串列表

时间:2019-03-13 11:26:36

标签: string list haskell split sequence

我正在尝试将一个字符串拆分为一系列序列,这些序列是该字符串的子字符串。有点难以解释,但是我会给你一个例子,以便您了解我在寻找什么。

我要从此字符串"123456789"中获得一个类似的列表:

["123", "234, "345, ..., "789", "891", "912"]

此刻,我只有一个函数可以将字符串分成该字符串的n部分的列表:

splitList :: Int -> [a] -> [[a]]
splitList _ [] = []
splitList n xs = as : splitList n bs
    where (as,bs) = splitAt n xs

3 个答案:

答案 0 :(得分:1)

我只使用takedrop的组合,并具有列表理解:

splitList :: Int -> [a] -> [[a]]
splitList n xs = [take n $ drop i $ xs ++ xs | i <- [0..(length xs - 1)]]

({xs ++ xs仅在那儿受到“循环”影响,可以调整为仅添加前(n-1)个元素,但我相信Haskell的懒惰应该意味着在其中没有效率损失这样)

答案 1 :(得分:1)

我会这样:

import Data.List
splitList n xs = zipWith const chunks xs where
    chunks = map (take n) . tails . cycle $ xs

这应该具有复杂度O(m * n),其中m是xs的长度,n是每个块的大小;天真的似乎很难做得更好,因为这就是输出的大小。它还巧妙地处理了许多尴尬的情况,包括明智地处理无限列表输入。

如果您以前从未见过zipWith const的窍门,那绝对是值得您添加的武器库之一。它使您可以执行与take (length xs) ys大致相同的操作,但无需事先实际计算length xs

答案 2 :(得分:1)

splitList :: Int -> [a] -> [[a]]
splitList n xs = zipWith const (map (take n) . tails . cycle $ xs) xs

-- splitList n = zipWith const =<< map (take n) . tails . cycle

-- splitList n = map (take n) . tails . cycle >>= zipWith const

可以完成这项工作,并且还可以在无限输入上工作,即适当地懒惰。

zipWith const代替了lengthtake,用列表元素代替了数字。

pointpoint变体甚至可以读懂/说明这里发生的事情。

(忘了,tails来自Data.List)。