Получить каждую комбинацию строк - PullRequest
3 голосов
/ 22 сентября 2009

У меня было комбинаторное задание, которое включало получение каждого слова длиной менее или равным 6 из определенной комбинации строк.

В данном случае это был S = {'a', 'ab', 'ba'}. Профессор только начал перечислять их, но я подумал, что это будет легче решить с помощью программы. Единственная проблема в том, что я не могу получить хороший алгоритм, который бы фактически вычислял все возможные варианты.

Если бы кто-нибудь мог помочь, я был бы благодарен. Я обычно программирую на Python, но на самом деле мне просто нужна помощь с алгоритмом.

Ответы [ 4 ]

9 голосов
/ 22 сентября 2009

Если вы действительно имеете в виду комбинации (без повторов, порядок не имеет значения):

import itertools

S = [ 'a', 'ab', 'ba' ]

for i in range(len(S)+1):
  for c in itertools.combinations(S, i):
    cc = ''.join(c)
    if len(cc) <= 6:
      print c

испускает все возможности:

()
('a',)
('ab',)
('ba',)
('a', 'ab')
('a', 'ba')
('ab', 'ba')
('a', 'ab', 'ba')

Если вы имеете в виду нечто иное, чем «комбинации», это просто вопрос использования правильного итератора или генератора в for (например, itertools.permutations, или что-то еще вашего собственного изобретения).

Редактировать : если, например, вы имеете в виду «повторы и порядок важны»,

def reps(seq, n):
  return itertools.product(*[seq]*n)

for i in range(7):
  for c in reps(S, i):
    cc = ''.join(c)
    if len(cc) <= 6:
      print c

даст вам необходимые 85 строк вывода.

Снова отредактируйте : у меня был неправильный предел цикла (и, следовательно, неправильная длина вывода) - tx комментатору, который указал на это. Кроме того, этот подход может создать строку> 1 раз, если '.join из разных кортежей считается эквивалентным; например, он производит ('a', 'ba') в отличие от ('ab', 'a'), хотя их.'join одинаковы (я полагаю, одно и то же слово из разных так называемых "комбинаций") - используемая терминология не совсем понятна).

8 голосов
/ 22 сентября 2009

Вы можете итеративно генерировать все строки, состоящие из одной части, двух частей, трех частей и т. Д., Пока все строки, созданные в шаге, не будут длиннее шести символов. Дальнейшие шаги будут генерировать только более длинные строки, поэтому все возможные короткие строки уже созданы. Если вы собираете эти короткие строки на каждом шаге, вы получаете набор всех возможных сгенерированных коротких строк.

В Python:

S = set(['a', 'ab', 'ba'])

collect = set()
step = set([''])
while step:
   step = set(a+b for a in step for b in S if len(a+b) <= 6)
   collect |= step

print sorted(collect)
3 голосов
/ 22 сентября 2009
def combos(S,n):
    if (n <= 0): return
    for s in S:
        if len(s) <= n: yield s
        for t in combos(S,n-len(s)): yield s+t

for x in combos(["a","ab","ba"],6): print x

Вывод на печать:

a
aa
aaa
aaaa
aaaaa
aaaaaa
aaaaab
aaaaba
aaaab
aaaaba
aaaba
aaabaa
aaab
aaaba
aaabaa
aaabab
aaabba
aaba
aabaa
aabaaa
aabaab
aababa
aab
aaba
aabaa
aabaaa
aabaab
aababa
aabab
aababa
aabba
aabbaa
aba
abaa
abaaa
abaaaa
abaaab
abaaba
abaab
abaaba
ababa
ababaa
ab
aba
abaa
abaaa
abaaaa
abaaab
abaaba
abaab
abaaba
ababa
ababaa
abab
ababa
ababaa
ababab
ababba
abba
abbaa
abbaaa
abbaab
abbaba
ba
baa
baaa
baaaa
baaaaa
baaaab
baaaba
baaab
baaaba
baaba
baabaa
baab
baaba
baabaa
baabab
baabba
baba
babaa
babaaa
babaab
bababa
1 голос
/ 22 сентября 2009

Рекурсивно это сделать одним из способов:

cache = {}
def words_of_length(s, n=6):
    # memoise results
    if n in cache: return cache[n]

    # base cases
    if n < 0: return []
    if n == 0: return [""]

    # inductive case
    res = set()
    for x in s:
        res |= set( (x+y for y in words_of_length(s, n-len(x))) )

    # sort and memoise result
    cache[n] = sorted(res)

    # sort results
    return cache[n]

def words_no_longer_than(s, n=6):
    return sum( [words_of_length(s, i) for i in range(n+1)], [] )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...