来自单个字符串的所有子序列

时间:2013-10-22 17:56:31

标签: haskell

如何从单个字符串中提取每个可能的子字符串? 我想出了一种简单的方法,想找一个更简单的方法。

subStrings :: String -> [String]
subStrings xs = xs : takeEl xs

takeEl :: String -> [String]
takeEl xs = nub (concat [y : (takeEl y) | y <- takeEl'])
  where 
    takeEl' = [del y xs | y <- [0..(length xs - 1)]]

del :: Int -> [a] -> [a]
del k xs = take k xs ++ drop (k+1) xs

我想用一个例子进一步解释一下: 如果我在“abc”上使用该函数,我希望它创建一个包含下面元素的列表,没有排列(如果“ab”不是“ba”,则不需要)。

`["abc", "a","b","c","ab","ac","bc",""]`

如此简洁。尾巴是不够的,因为它不会给我“ac”。

5 个答案:

答案 0 :(得分:5)

Data.List模块提供subsequences,这是正确的名称。 (子串是连续的。)

答案 1 :(得分:2)

编辑:以下计算原始问题中提到的子字符串,而不是子序列


如果你正在寻找快速的东西(并不一定尽可能高效),我建议这就是:

import Data.List (inits, tails)

nonEmptySubstrings :: [a] -> [[a]]
nonEmptySubstrings = concatMap (tail . inits) . tails

需要tail来完全消除空子串;否则会发生多次。如果你也想要它,你将不得不额外添加它。

substrings :: [a] -> [[a]]
substrings = ([] :) . nonEmptySubstrings

示例:

Prelude Data.List> nonEmptySubstrings "abcd"
["a","ab","abc","abcd","b","bc","bcd","c","cd","d"]
Prelude Data.List> substrings "abcd"
["","a","ab","abc","abcd","b","bc","bcd","c","cd","d"]

答案 2 :(得分:2)

你可以通过采取所有尾部的可能头部或所有头部的所有可能的尾部来做到这一点。

这是有效的,因为所有子串都由2个事物,位置和长度唯一确定。当您使用tails删除所有可能的头时,您将从每个可能的位置开始使用最长可能的长度,然后将inits应用于所有这些返回所有可能的长度,将这些组合起来可能的子串。反向的想法非常相似。

所以你可以使用nickie的

concatMap inits . tails

或者

concatMap tails . inits

由于>>=concatMap相同,因此您可以编写

tails <=< inits -- From control.monad

答案 3 :(得分:1)

看起来你所追求的不是所有子序列的列表,而是所有子集的列表(保持原始顺序) - power set。这可以通过列表monad中的一个很好的技巧来实现:

filterM (const [False, True]) "abc"

产量

["","c","b","bc","a","ac","ab","abc"]

诀窍是我们非确定性地过滤列表monad中的给定列表,分支以保留和删除特定元素。

答案 4 :(得分:0)

如果您不想在Prelude之外使用功能,请使用以下方法:

#file

这绝对不是最有效的方法。只是对性能不敏感的任务的一种简单而肮脏的方法

但是,OP最初的问题是subsequences,而不是子字符串。