2009-02-16 6 views
5

Я пытаюсь сгенерировать morris sequence в python. Мое текущее решение ниже, но я чувствую, что просто написал c в python. Может ли кто-нибудь предоставить более pythonic решение?Может ли кто-нибудь предоставить более pythonic способ генерации последовательности morris?

def morris(x): 
    a = ['1', '11'] 
    yield a[0] 
    yield a[1] 
    while len(a) <= x: 
     s = '' 
     count = 1 
     al = a[-1] 
     for i in range(0,len(al)): 
      if i+1 < len(al) and al[i] == al[i+1]: 
       count += 1 
      else: 
       s += '%s%s' % (count, al[i]) 
       count = 1 
     a.append(s) 
     yield s 
a = [i for i in morris(30)] 
+0

Это звучит как йо Вы спрашиваете о том, как тащит рыбу. Это сочетает в себе Monty Python и Morris Dancing ... :-) –

+0

Если бы эта вещь не требовала не менее 10 символов, я бы просто ответил: D –

+0

Почему вы оба уступаете() и сохраняете значения на [] ? – Javier

ответ

23

itertools.groupby кажется идеально подходит! Просто определить next_morris функцию следующим образом:

def next_morris(number): 
    return ''.join('%s%s' % (len(list(group)), digit) 
        for digit, group in itertools.groupby(str(number))) 

Это все !!! Смотри:

print next_morris(1) 
11 
print next_morris(111221) 
312211 

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

def morris_generator(maxlen, start=1): 
    num = str(start) 
    while len(num) < maxlen: 
     yield int(num) 
     num = next_morris(num) 

Использование:

for n in morris_generator(10): 
    print n 

результаты:

1 
11 
21 
1211 
111221 
312211 
13112221 
+0

большое спасибо. мне действительно нужно узнать библиотеку iterools лучше –

6
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)) 

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

Тогда, очевидно, нет необходимости хранить весь список предыдущих чисел morris в списке, поскольку рекурсия только n := f(n-1) в любом случае.

И наконец, использование itertools для придания ему функционального прикосновения всегда стоит подпрыгнуть или два;) Я разделил выражение генератора на несколько строк, чтобы сделать его немного легче на глазу.

Главное уродство в этом решении происходит из-за того, что len() нельзя вызывать на итераторе и дает нам int, где нам нужна str. Другой hickup - вложенный 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 

Надеюсь, вам понравится!