是否有一个内置函数来获取Haskell中列表大小为n的所有连续子序列?

是否有一个内置函数来获取Haskell中列表大小为n的所有连续子序列?,haskell,Haskell,例如,我需要一个函数: gather :: Int -> [a] -> [[a]] gather n list = ??? 其中收集3个“Hello!”=[“Hel”,“ell”,“llo”,“ol!”] 我有一个工作实现: gather :: Int-> [a] -> [[a]] gather n list = unfoldr (\x -> if fst x + n > length (snd x) t

例如,我需要一个函数:

gather :: Int -> [a] -> [[a]]
gather n list = ???
其中
收集3个“Hello!”=[“Hel”,“ell”,“llo”,“ol!”]

我有一个工作实现:

gather :: Int-> [a] -> [[a]]
gather n list = 
    unfoldr 
        (\x -> 
            if fst x + n > length (snd x) then 
                Nothing 
            else 
                Just 
                    (take 
                        n 
                        (drop 
                            (fst x)
                            (snd x)), 
                    (fst x + 1, snd x))) 
        (0, list)

但是我想知道,语言中是否已经包含了用于此目的的内容?我扫描了数据,但什么都没看到

您可以使用
尾部

gather n l = filter ((== n) . length) $ map (take n) $ tails l
或者使用
takeWhile
而不是
filter

gather n l = takeWhile ((== n) . length) $ map (take n) $ tails l
编辑:您可以删除筛选步骤,方法是按照注释中的建议,删除从
tails
返回的列表的最后
n
元素:

gather n = map (take n) . dropLast n . tails
  where dropLast n xs = zipWith const xs (drop n xs)

由于拉链的特性,尾巴的下落可以自动安排

或者一个简单的
转置。以n为例。尾巴就足够了。测试:

序曲数据列表>g 3[1..10]
[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8],[7,8,9],[8,9,10]
前奏曲数据。列表>转置。拿3块。尾部$[1..10]
[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8,8,9],[8,9,10],[9,10]]


(编辑2018-09-16:)拉链的使用可以在更高的层次上表达,使用
traverse ZipList

g :: Int -> [a] -> [[a]]
g n = getZipList . traverse ZipList . take n . tails

我会使用
takeWhile
而不是
filter
,但这是一个相当温和的优化。这在语义上似乎是正确的,但在操作上有点粗糙:检查每个子列表的长度似乎工作量太大。有一个标准的技巧可以说“除了列表的最后一个
n
元素之外,其余元素都要接受”,这就是
\xs->zipWith const xs(drop n xs)
;也许你可以在这里使用这个技巧。@DanielWagner-谢谢你的建议,这更简洁了。我非常喜欢这两种方法,因为它们同时处理字符串和Int列表。调用参数可以改进,但这并不重要。我的将执行Int,但不执行没有附加逻辑的字符串。。。。gv no sz=zipWith enumFromTo[1..no][sz..]>>>>gv 3 4用于一个包含3个四元素列表的列表。这里的要点是重新排列给定列表,而不是重新创建它
zipWith enumFromTo
创建模拟结果的整数列表,但是如果我们必须重新排列排序([1,4..20]+[1,5..30])
?重新排列忽略了元素的性质,只是操纵列表结构,而不管它包含什么。就像列表是一个盒子链(每个盒子里都有一些元素),我们是在处理盒子,而不是它们里面的东西。(这些框实际上并不包含值,而是包含指向这些值的指针——每个框都包含一个指针)。这就是Haskell的意思,当我们说“
[a]
是一个参数类型,一个“某物”的“列表”,不管它是什么”——在类型
[]中,某物是参数,
a
a
[a]
。因此,当我们重新排列一个列表时,我们会创建新的“列表结构”,即新的框链,将新指针指向原始框中的相同值。就像在Lisp中一样。在Lisp中,可以使用
set car更改框的指针
设置cdr。哈斯克尔的情况并非如此。但从概念上讲,这个模型可以防止在重新排列时过度复制值,如果我们说有实际包含值的框,这将是不可避免的(新链将在其框中保存值的副本)。当然,在Haskell中,由于其引用透明性,复制的值无法与指向相同值的新指针(具有正常的Haskell值)区分开来,除了性能影响(内存大小、速度、GC(垃圾收集)数量等)。[#t、#t、#t]Racket forwent set car等。正如您所说,它违反了,Ref透明性和不变性。现在,我看到列表是必需的参数。递归函数使用tail。取&length。我更喜欢下面的递归,它可以处理任何列表或字符串,非常感谢。g2 sz ls=[取sz t | t=sz]
g :: Int -> [a] -> [[a]]
g n = getZipList . traverse ZipList . take n . tails