【问题标题】:Getting all combinations of a string and its substrings获取字符串及其子字符串的所有组合
【发布时间】:2018-07-26 11:51:46
【问题描述】:

我见过很多关于获取所有可能的子字符串(即相邻字符集)的问题,但没有看到关于生成所有可能的字符串(包括其子字符串的组合)的问题。

例如,让:

x = 'abc'

我希望输出类似于:

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

重点是我们可以去掉原字符串中不相邻的多个字符(以及相邻的)。

这是我迄今为止尝试过的:

def return_substrings(input_string):
    length = len(input_string)
    return [input_string[i:j + 1] for i in range(length) for j in range(i, length)]

print(return_substrings('abc'))

但是,这只会从原始字符串中删除相邻字符串的集合,并且不会返回上例中的元素 'ac'

另一个例子是如果我们使用字符串'abcde',输出列表应该包含'ace''bd'等元素。

【问题讨论】:

  • 真的想以艰难的方式做到这一点吗?使用标准的itertools.combinations 函数很容易做到,而且运行速度也更快。
  • 这基本上是whats a good way to find power_set 的字符串版本。 stackoverflow.com/questions/1482308/…
  • 这些是组合,而不是“迭代”。组合基本上是顺序无关紧要的子集。如果顺序很重要,那就是排列。
  • @MikeHousky 谢谢指正,我改一下标题。
  • 如果您想处理像 "AAAA" 这样的字符串并且没有不必要的重复,请查看我的答案。

标签: python string


【解决方案1】:

您可以使用itertools.combinations轻松做到这一点

>>> from itertools import combinations
>>> x = 'abc'
>>> [''.join(l) for i in range(len(x)) for l in combinations(x, i+1)]
['a', 'b', 'c', 'ab', 'ac', 'bc', 'abc']

如果你想要它以相反的顺序,你可以让range函数以相反的顺序返回它的顺序

>>> [''.join(l) for i in range(len(x),0,-1) for l in combinations(x, i)]
['abc', 'ab', 'ac', 'bc', 'a', 'b', 'c']

【讨论】:

  • @PM2Ring .. 更新了答案以使 o/p 也以相反的顺序进行
  • 另外,不应该是len(x) 而不是len(s) 吗?
  • @scharette。谢谢...应该是len(x)
【解决方案2】:

这是一个有趣的练习。我认为其他答案可能会使用 itertools.product 或 itertools.combinations。但只是为了好玩,您也可以使用类似的方法递归地执行此操作

def subs(string, ret=['']):
    if len(string) == 0:
        return ret
    head, tail = string[0], string[1:]
    ret = ret + list(map(lambda x: x+head, ret))
    return subs(tail, ret)

subs('abc')
# returns ['', 'a', 'b', 'ab', 'c', 'ac', 'bc', 'abc']

【讨论】:

  • 虽然 Python 自带“含电池”,但大家看看如何递归完成这个任务肯定是有好处的。现在看看是否可以在不使用排序的情况下按照问题中显示的顺序获得输出。 :邪恶的笑容:
  • @PM2Ring 也许我的答案和他的合并可以做到;)
【解决方案3】:

@Sunitha answer 提供了正确的工具来使用。在使用您的 return_substrings 方法时,我会建议一种改进的方法。基本上,我的解决方案会处理重复项


我将使用"ABCA" 来证明我的解决方案的有效性。请注意,它会在接受的答案的返回列表中包含重复的'A'

Python 3.7+ 解决方案

x= "ABCA"
def return_substrings(x):
    all_combnations = [''.join(l) for i in range(len(x)) for l in combinations(x, i+1)]
    return list(reversed(list(dict.fromkeys(all_combnations))))
    # return list(dict.fromkeys(all_combnations)) for none-reversed ordering

print(return_substrings(x))
>>>>['ABCA', 'BCA', 'ACA', 'ABA', 'ABC', 'CA', 'BA', 'BC', 'AA', 'AC', 'AB', 'C', 'B', 'A']

Python 2.7 解决方案

您必须使用OrderedDict 而不是普通的dict。因此,

 return list(reversed(list(dict.fromkeys(all_combnations))))

变成

return list(reversed(list(OrderedDict.fromkeys(all_combnations))))

顺序与您无关?

如果顺序不相关,您可以降低代码复杂度,

x= "ABCA"
def return_substrings(x):
    all_combnations = [''.join(l) for i in range(len(x)) for l in combinations(x, i+1)]
    return list(set(all_combnations))

【讨论】:

    【解决方案4】:
    def return_substrings(s):
        all_sub = set()
        recent = {s}
    
        while recent:
            tmp = set()
            for word in recent:
                for i in range(len(word)):
                    tmp.add(word[:i] + word[i + 1:])
            all_sub.update(recent)
            recent = tmp
    
        return all_sub
    

    【讨论】:

      【解决方案5】:

      对于已接受答案的过度杀伤/不同版本(使用 https://docs.python.org/3/library/itertools.html#itertools.product 表达组合):

      ["".join(["abc"[y[0]] for y in x if y[1]]) for x in map(enumerate, itertools.product((False, True), repeat=3))]
      

      为了更直观的解释,将所有子串视为长度为n的所有位串的映射。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-25
        • 2012-08-16
        • 1970-01-01
        • 2012-09-14
        • 1970-01-01
        • 2022-08-17
        • 1970-01-01
        相关资源
        最近更新 更多