如何列出子字符串?

时间:2014-12-16 17:55:23

标签: string haskell recursion

我正在尝试列出所有子字符串,其中每个子字符串只有一个原始字符串元素。

例如" 1234"会导致[" 1234"," 123"," 12"," 1"]

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

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

slist :: String -> [String]
slist (x:xs) = (take (length (x:xs)) (x:xs)) ++ slist xs

如何使用

递归执行此操作

编辑:想通过递归使用init来实现这个目标

4 个答案:

答案 0 :(得分:3)

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

main = do 
    print $ slist "1234"

答案 1 :(得分:1)

这是一个非常懒惰的版本,适合处理无限列表。每个结果列表在第一个之后的每个元素只需要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)

splits查找列表的所有初始序列以及尾随列表。

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

我们可以根据相同的策略从列表末尾写下来。

dropEnd :: Int -> [a] -> [a]
dropEnd n = uncurry (shiftThrough . fromList) . splitAt n

这些使用Data.SequenceO(n)的序列fromList构建O(1)|>附加到O(1)和{{1}的序列末尾用viewl检查序列的开始。

这足够快,可以在几秒钟内快速查询(starts [1..]) !! 80000之类的内容和(starts [1..]) !! 8000000

看马,没有进口

队列的一个简单的纯功能实现是一对列表,一个包含按顺序输出next的内容,另一个包含最新的内容added。每当添加某些内容时,它都会添加到added列表的开头。当需要某些内容时,该项目将从next列表的开头删除。如果没有其他项目可以从next列表中删除,则会以相反的顺序替换为added列表,added列表将设置为[]。这已经摊销O(1)运行时间,因为每个项目将被添加一次,删除一次,然后反转一次,但是许多反转将同时发生。

delay使用上述队列逻辑实现与上一节shiftThrough相同的操作。 xs是最近added项内容的列表,ys是要使用的内容列表next

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几乎是一次扫描

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

我们可以使用starts和另一个返回列表的delay版本来定义splits

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的实现非常相似。

答案 2 :(得分:0)

这是一个有点复杂的版本:

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"

答案 3 :(得分:0)

更新了答案,列出了所有可能的子字符串(不仅仅是从根目录开始)。

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"]