在所有可能的“子词”中分割单词-所有可能的组合(不包括导入)

时间:2019-03-24 15:29:13

标签: haskell recursion haskell-platform

我正在尝试以以下方式获取单词的所有可能组合,而无需使用任何导入:

例如...

    Input: Bang

    Output: [['B','ang'], ['Ba','ng'], ['Ban','g'], ['B','a','ng'], ['B','an','g'], ['Ba','n','g'], ['B','a','n','g']]

这个问题困扰了我一段时间,我似乎无法弄清楚执行此操作的算法。

下面的代码是我所做的,但这给出了字符串的所有可能组合,但不是我所需要的方式。

我试图在haskell中实现此python代码,但无法完成。基本上是相同的问题,但是在haskell中没有循环。

Splitting a word into all possible 'subwords' - All possible combinations

下面的代码输出是...

[“ sun”,“ su”,“ s”,“ un”,“ u”,“ n”]

不是

[[“ s”,“ un”],[“ s”,“ u”,“ n”],[“ su”,“ n”]]

    -----------------------------------------------------


    substring :: String -> [String]
    substring [] = []
    substring xs = subs xs ++ substring (tail xs)
            where
               subs xs = foldl step [] xs
               step [] a = [[a]]
               step acc a = (head acc ++ [a]) : acc

    ---------------EXAMPLES OF EXPECTED RESULTS BELOW----------------------------------
    Input: Bang
    Output: [['B','ang'], ['Ba','ng'], ['Ban','g'], ['B','a','ng'], ['B','an','g'], ['Ba','n','g'], ['B','a','n','g']]

    Input: Sun
    Output: [["s","un"],["s","u","n"],["su","n"]]

2 个答案:

答案 0 :(得分:2)

请注意,您尝试的类型签名是错误的。您需要所有子词拆分的组合,这是一个字符串列表的列表,但是您的类型只是一个字符串列表的列表。

这将起作用:

onHead :: (a -> a) -> [a] -> [a]
onHead _ [] = []
onHead f (x:xs) = f x:xs

combos :: [a] -> [[[a]]]
combos [] = [[]]
combos [x] = [[[x]]]
combos (x:xs) = [([x]:), onHead (x:)] <*> combos xs

onHead应该是不言自明的:在列表的开头执行给定的功能。 combos的重复过程如下:字符串的子词是其尾部的子词,每个子词都有两种可能性:头是其自己的子词,或者被钉在第一个子词的开头。


更新:这是另一种(IMO清洁器)方法:

combos :: Foldable t => t a -> [[[a]]]
combos = foldr (concatMap . go) [[]]
  where go x l = ([x]:l):case l of
          [] -> []
          h:t -> [(x:h):t]

它使用与上述相同的技术,只是实现了更简洁的实现。

答案 1 :(得分:1)

递归可以为您提供帮助。假设我们有一个非空列表x : xs。我们想知道subString (x : xs)。我们将解决方案递归应用于xs,因此subString xsxs的所有解决方案的列表。但是,我们仍然只有那个x。完全有两种方法可以将x的解决方案带回x : xs,其中涵盖了subString (x : xs)的整个解决方案集:

  • x带回而没有将其附加到其邻居。如果我们有x : xs = "Bang",则x将是'B',而xs将是"ang",而subString "ang"将是[["ang"],["an","g"],["a","ng"],["a","n","g"]]。这是由[[x] : u | u <- subString xs]完成的。这里的u是字符串列表,例如["a","ng"]。因为x是一个字符,所以我们必须将其转换为字符串,这是通过[x]完成的,将其附加到列表的开头是[x] : u,因此["B","a","ng"]。列表推导将对subString xs中的所有元素执行此操作。
  • x重新附加到其邻居。 subString xs的任意解决方案看起来像u : us。我们想将x附加到u : us的第一个元素u上。 x : u这样。例如u : us = ["a","n","g"],因此u将是"a",而us将是["n","g"]。将'B'附加到"a"'B' : "a"完成,将得到"Ba"。我们必须将"Ba放回列表中,以便(x : u) : us。列表comp [rehension看起来像[(x : u) : us | (u : us) <- subString xs]

我们仍然只剩下一个字符的字符串。我们为此写[x],其中x是单个字符。因此subString [x]将是[[[x]]]

我们必须将解决方案结合在一起

subString :: String -> [[String]]
subString   [x]    = [[[x]]]
subString (x : xs) = [(x : u) : us | (u : us) <- subString xs] ++ [[x] : u | u <- subString xs]

示例

*Main> subString "Bang"
[["Bang"],["Ban","g"],["Ba","ng"],["Ba","n","g"],["B","ang"],["B","an","g"],["B","a","ng"],["B","a","n","g"]]