我正在尝试将一个字符串拆分为一系列序列,这些序列是该字符串的子字符串。有点难以解释,但是我会给你一个例子,以便您了解我在寻找什么。
我要从此字符串"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
答案 0 :(得分:1)
我只使用take
和drop
的组合,并具有列表理解:
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
代替了length
和take
,用列表元素代替了数字。
pointpoint变体甚至可以读懂/说明这里发生的事情。
(忘了,tails
来自Data.List
)。