from itertools import groupby, islice
def morris():
morris = '1'
yield morris
while True:
morris = groupby(morris)
morris = ((len(list(group)), key) for key, group in morris)
morris = ((str(l), k) for l, k in morris)
morris = ''.join(''.join(t) for t in morris)
yield morris
print list(islice(morris(), 10))
Прежде всего я бы сделал итератор бесконечным и позволил бы потребителю решать, сколько он хочет. Таким образом, он мог либо получить каждое число Морриса, которое короче x, либо первые x числа и т. Д.
Тогда, очевидно, нет необходимости хранить весь список предыдущих чисел Морриса в списке, так как рекурсия в любом случае только n := f(n-1)
.
Наконец, использование itertools для придания ему функциональности всегда стоит того, чтобы разобраться с ним; два;) Я разбил выражение генератора на несколько строк, чтобы сделать его немного более привлекательным.
Главное уродство в этом решении проистекает из того факта, что len()
не может быть вызван итератором и дает нам int, где нам нужна str. Другой хит - это вложенный str.join), чтобы снова сплющить все это в str.
Если вы хотите начать последовательность с произвольных чисел, определите функцию следующим образом:
def morris(morris=None):
if morris is None:
morris = '1'
[...]
Если вы хотите развернуть этот генератор, вы можете написать его так:
def morris():
morris = '1'
yield morris
while True:
print morris
morris = ''.join(''.join(t)
for t in ((str(len(list(group))), key)
for key, group in groupby(morris)))
yield morris
Я не уверен, что мне нравится разделение на две функции, но это, кажется, самое читаемое решение:
def m_groupby(s):
for key, group in groupby(s):
yield str(len(list(group)))
yield key
def morris():
morris = '1'
yield morris
while True:
morris = ''.join(m_groupby(morris))
yield morris
Надеюсь, вам понравится!