Получение всех комбинаций строки и ее подстрок

Я видел много вопросов о получении всех возможных подстрок (т.е. Смежных наборов символов), но ни один из них не генерировал все возможные строки, включая комбинации его подстрок.

Например, пусть:

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' и т.д.

Ответы

Ответ 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']

Ответ 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']

Ответ 3

@Sunitha ответ предоставил правильный инструмент для использования. Я просто пойду и предложу улучшенный способ при использовании вашего метода 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