String 如何列出子字符串?

String 如何列出子字符串?,string,haskell,recursion,String,Haskell,Recursion,我试图列出所有子字符串,其中每个子字符串的原始字符串中少了一个元素 e、 g“1234”将导致[“1234”、“123”、“12”、“1”] 我想实现这一点,只使用前奏(无导入),所以不能使用子序列 我是Haskell的新手,我知道代码中的一些问题,但目前不知道如何修复它们 slist :: String -> [String] slist (x:xs) = (take (length (x:xs)) (x:xs)) ++ slist xs 如何使用 编辑:希望通过递归使用init来解决

我试图列出所有子字符串,其中每个子字符串的原始字符串中少了一个元素

e、 g“1234”将导致[“1234”、“123”、“12”、“1”]

我想实现这一点,只使用前奏(无导入),所以不能使用子序列

我是Haskell的新手,我知道代码中的一些问题,但目前不知道如何修复它们

slist :: String -> [String]
slist (x:xs) = (take (length (x:xs)) (x:xs)) ++ slist xs
如何使用


编辑:希望通过递归使用init来解决此问题,这里有一个有点复杂的版本:

slist :: String -> [String]
slist [] = []
-- slist xs = [xs] ++ (slist $ init xs)
slist xs = xs : (slist $ init xs)

main = do 
    print $ slist "1234"
slist xs = go (zip (repeat xs) [lenxs, lenxs - 1..1])
  where lenxs = length xs
        go [] = []
        go (x:xs) = (take (snd x) (fst x)) : go xs

main = do 
    print $ slist "1234"

这里有一个非常懒惰的版本,适合处理无限列表。在第一个元素之后的每个结果列表的每个元素只需要
O(1)
摊销时间来计算它,无论我们看列表有多远

总体思路是:对于每个长度
n
我们打算从末尾退出,我们将列表分成一个长度
n
的项目队列和列表的其余部分。为了产生结果,我们首先检查列表中是否有另一个项目可以在队列中占有一席之地,然后产生队列中的第一个项目。当我们到达列表的末尾时,我们将丢弃队列中剩余的项目

import Data.Sequence (Seq, empty, fromList, ViewL (..), viewl, (|>))

starts :: [a] -> [[a]]
starts = map (uncurry shiftThrough) . splits

shiftThrough :: Seq a -> [a] -> [a]
shiftThrough queue [] = []
shiftThrough queue (x:xs) = q1:shiftThrough qs xs 
    where
        (q1 :< qs) = viewl (queue |> x)
我们可以用同样的策略从列表的末尾写下删除

dropEnd :: Int -> [a] -> [a]
dropEnd n = uncurry (shiftThrough . fromList) . splitAt n
这些使用分期摊销的
O(n)
从列表
构建序列
fromList
O(1)
|>
附加到序列的末尾,以及
O(1)
viewl
检查序列的开头

这足够快,可以查询
(开始[1])之类的内容!!80000
非常快且
(开始[1])!!8000000
在几秒钟内完成

听着,妈妈,没有进口货 队列的一个简单的纯功能实现是一对列表,一个包含要按顺序输出的
next
,另一个包含最近添加的
。无论何时添加内容,它都会添加到
added
列表的开头。当需要某样东西时,该项目将从
next
列表的开头删除。当
下一个
列表中没有剩余的要删除的项目时,它将按相反顺序被
添加的
列表替换,并且
添加的
列表设置为
[]
。这已经摊销了运行时间,因为每个项目将添加一次、删除一次和反转一次,但是许多反转将同时发生

delay
使用上述队列逻辑实现与上一节中的
shift through
相同的功能
xs
是最近添加的
内容列表
ys
是下一步使用的
内容列表

delay :: [a] -> [a] -> [a]
delay ys = traverse step ([],ys)
    where
        step (xs, ys) x = step' (x:xs) ys
        step' xs []     = step' [] (reverse xs)
        step' xs (y:ys) = (y, (xs, ys))
遍历
几乎就是一次扫描

traverse :: (s -> a -> (b, s)) -> s -> [a] -> [b]
traverse f = go
    where
        go _ []     = []
        go s (x:xs) = y : go s' xs
            where (y, s') = f s x
我们可以根据
delay
和另一个返回列表的
splits
版本定义
start

starts :: [a] -> [[a]]
starts = map (uncurry delay) . splits

splits :: [a] -> [([a], [a])]
splits = go []
    where
        go s []     = []
        go s (x:xs) = (reverse s, x:xs):go (x:s) xs

这与使用更新的答案列出所有可能的子字符串(而不仅仅是从根开始)的
Seq
实现的性能非常相似


所以你想要
init。相反。初始化
?这需要
数据。List
,但是你可以去看看源代码,看看如何自己实现它。另外,我建议将
inits
作为第一个结果,相关的
tails
函数就在这里。4.编写此函数的惰性版本是一个有趣的挑战。建议编辑:
slist xs=xs:(slist$init xs)
++
更昂贵:
这列出了从1开始的所有子字符串,但不是所有子字符串。OP仅使用Prelude(无导入)指定。不过回答不错。
starts :: [a] -> [[a]]
starts = map (uncurry delay) . splits

splits :: [a] -> [([a], [a])]
splits = go []
    where
        go s []     = []
        go s (x:xs) = (reverse s, x:xs):go (x:s) xs
slist :: [t] -> [[t]]
slist [] = []
slist xs = xs : (slist $ init xs )  # Taken from Pratik Deoghare's post


all_substrings:: [t] -> [[t]]
all_substrings (x:[]) = [[x]]
all_substrings (x:xs)  = slist z ++ all_substrings xs
                         where z = x:xs

λ> all_substrings "1234"
["1234","123","12","1","234","23","2","34","3","4"]