2

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

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

所以 concat inits 。tails 是不够的,因为它不会给我“ac”。

4

5 回答 5

5

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

于 2013-10-22T22:30:47.147 回答
3

编辑: 以下计算substrings,这是在原始问题中提到的,而不是subsequences


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

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"]
于 2013-10-22T18:08:08.893 回答
2

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

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

所以你可以使用 nickie's

concatMap inits . tails

或者

concatMap tails . inits

既然>>=是一样的concatMap,你可以写

tails <=< inits -- From control.monad
于 2013-10-22T18:30:16.227 回答
1

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

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

产量

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

诀窍是我们在列表单子中不确定地过滤给定列表,分支以保留和删除特定元素。

于 2014-02-07T19:44:16.710 回答
0

如果您不想在 Prelude 之外使用函数,请使用以下命令:

substrings x = [drop b (take a x) | a <- [1..length x], b <- [0..a-1]]

这绝对不是最有效的方法。只是一个快速而肮脏的单线,用于对性能不敏感的任务

但是,OP 的原始问题意味着子序列而不是子字符串。

于 2020-06-13T07:12:04.283 回答