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

iob*_*der 5 haskell

例如,我需要一个功能:

gather :: Int -> [a] -> [[a]]
gather n list = ???
Run Code Online (Sandbox Code Playgroud)

哪里gather 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)
Run Code Online (Sandbox Code Playgroud)

但是我想知道这种语言中是否已经内置了一些内容?我扫描了Data.List但没有看到任何内容.

Lee*_*Lee 14

你可以使用tails:

gather n l = filter ((== n) . length) $ map (take n) $ tails l
Run Code Online (Sandbox Code Playgroud)

或使用takeWhile而不是filter:

gather n l = takeWhile ((== n) . length) $ map (take n) $ tails l
Run Code Online (Sandbox Code Playgroud)

编辑:您可以通过删除评论中建议的n返回列表的最后元素来删除过滤器步骤tails:

gather n = map (take n) . dropLast n . tails
  where dropLast n xs = zipWith const xs (drop n xs)
Run Code Online (Sandbox Code Playgroud)

  • 这似乎在语义上是正确的,但在操作上有点粗糙:检查每个子列表的长度似乎太多了.有一个标准的技巧可以说"除列表的最后一个`n`元素外",即`\ xs - > zipWith const xs(drop n xs)`; 也许你可以在这里使用这个技巧. (8认同)

Wil*_*ess 5

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

import Data.List (tails)

g :: Int -> [a] -> [[a]]
g n = foldr (zipWith (:)) (repeat []) . take n . tails
Run Code Online (Sandbox Code Playgroud)

或者简单transpose . take n . tails就足够了.测试:

Prelude Data.List> 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]]
Prelude Data.List> transpose.拿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],[9,10],[10]]


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

g :: Int -> [a] -> [[a]]
g n = getZipList . traverse ZipList . take n . tails
Run Code Online (Sandbox Code Playgroud)