Нещодавно я написав функцію генерування певних послідовностей з нетривіальними обмеженнями. Проблема виникла з природним рекурсивним рішенням. Зараз буває так, що навіть при порівняно невеликому введенні послідовностей є кілька тисяч, тому я вважаю за краще використовувати свій алгоритм як генератор, а не використовувати його для заповнення списку всіма послідовностями.
Ось приклад. Припустимо, ми хочемо обчислити всі перестановки рядка з рекурсивною функцією. Наступний наївний алгоритм займає додатковий аргумент "сховище" і додає до нього перестановку, коли він знайде його:
def getPermutations(string, storage, prefix=""):
if len(string) == 1:
storage.append(prefix + string) # <-----
else:
for i in range(len(string)):
getPermutations(string[:i]+string[i+1:], storage, prefix+string[i])
storage = []
getPermutations("abcd", storage)
for permutation in storage: print permutation
(Будь ласка, не дбайте про неефективність. Це лише приклад.)
Тепер я хочу перетворити свою функцію в генератор, тобто отримати перестановку замість додавання її до списку пам’яті:
def getPermutations(string, prefix=""):
if len(string) == 1:
yield prefix + string # <-----
else:
for i in range(len(string)):
getPermutations(string[:i]+string[i+1:], prefix+string[i])
for permutation in getPermutations("abcd"):
print permutation
Цей код не працює (функція поводиться як порожній генератор).
Я щось пропускаю? Чи є спосіб перетворити вищезазначений рекурсивний алгоритм у генератор, не замінивши його на ітеративний ?
yield from getPermutations(string[:i] + string[i+1:])
, що є більш ефективним у багатьох аспектах!