У меня есть следующий список:

['a', 'b', 'c']

Я ищу способ генерировать все возможные строки, которые содержат эти символы со следующими ограничениями:

  • символ не может встречаться несколько раз (aab, aba, abca и т. д. недопустимо)
  • символ может быть исключен (ab действителен, даже если c отсутствует; a также действителен, даже если b и c отсутствуют)

Я могу использовать

[''.join(p) for p in permutations('abc')]

Генерировать все строки, которые содержат a, b и c. Однако я должен также сделать

[''.join(p) for p in permutations('ab')]
[''.join(p) for p in permutations('ac')]
[''.join(p) for p in permutations('bc')]

Как вы, вероятно, можете сказать, если первоначальный список доступных символов длинный, мне нужно проделать большую работу. Поэтому я ищу элегантный способ в Python для генерации всего вышеперечисленного с использованием только списка разрешенных символов в качестве входных данных:

def generate(vals=['a', 'b', 'c']):
  # The initial list of allowed characters also has to be part of the 
  # final list since these also represent valid values
  res = vals
  # Generate all possible strings and store in res

  return res

Мне это нужно, поскольку я хочу предоставить параметр для запроса POST для моего веб-сервера, где параметр (назовем его val) может принимать разные уникальные значения (либо отдельные символы, либо их комбинацию), чтобы вызвать генерацию некоторых данных. Список доступных значений со временем будет увеличиваться, поэтому я хотел бы упростить обработку запроса, автоматизировав проверку, если заданные значения для val являются допустимыми.

Я также думал об итерациях по каждому элементу списка разрешенных символов и объединении его с остальными («a», «ab», «ac», «abc», «b», «ba», «bc»). и т.д.) но я понятия не имею, как это сделать.

5
rbaleksandar 1 Мар 2018 в 18:35

3 ответа

Лучший ответ

Есть правильные ответы, которые уже были опубликованы, но я хотел дать ему шанс сделать его максимально читабельным.

from itertools import permutations as p

def gen(lst):
    y = [[a for a in p(lst,y)] for y in range(1,len(lst)+1)]

    this = []
    for i in y:
        while len(i)>0:
            this.append(i.pop())
    return [''.join(x) for x in this]

print(gen(['a','b','c']))
1
Işık Kaplan 1 Мар 2018 в 16:17

Вы можете использовать рекурсию с выражением генератора:

def permutation(s, current = []):
   if len(current) == len(s):
      yield current
   else:
      yield current
      for i in s:
        if current.count(i) == 0:
            for h in permutation(s, current + [i]):
               yield h

print(map(''.join, list(permutation(['a', 'b', 'c']))[1:]))

Выход:

['a', 'ab', 'abc', 'ac', 'acb', 'b', 'ba', 'bac', 'bc', 'bca', 'c', 'ca', 'cab', 'cb', 'cba']
1
Ajax1234 1 Мар 2018 в 15:44

Я бы связал различные перестановки строковых символов с ограничением длины:

import itertools

def generate(vals="abc"):
    return ("".join(x) for x in itertools.chain.from_iterable(itertools.permutations(vals,i+1) for i in range(0,len(vals))))

print(list(generate("abc"))) # force iteration to print result

Результат:

['a', 'b', 'c', 'ab', 'ac', 'ba', 'bc', 'ca', 'cb', 'abc', 'acb', 'bac', 'bca', 'cab', 'cba']

Изменить: кажется, что я создал вариант рецепта powerset (что хороший способ объединить через набор?), не считая пустую строку, учитывая порядок символов (abc и cba являются двумя разными элементами) и используя str.join генерировать строки напрямую.

2
Jean-François Fabre 1 Мар 2018 в 15:43