2009-02-16 13 views
5

Ich versuche, die morris sequence in Python zu generieren. Meine aktuelle Lösung ist unten, aber ich habe das Gefühl, dass ich gerade C in Python geschrieben habe. Kann jemand eine pythischere Lösung anbieten?Kann jemand eine pythischere Art der Erzeugung der Morris-Sequenz bereitstellen?

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

Es klingt wie yo Du fragst nach dem Fischschlag-Tanz. Das kombiniert Monty Python und Morris Dancing ... :-) –

+0

Wenn dieses Ding nicht mindestens 10 Zeichen benötigt, hätte ich nur geantwortet mit: D –

+0

Warum gibt ihr beide() ing und speichert Werte auf einem [] ? – Javier

Antwort

23

itertools.groupby scheint perfekt zu passen! Gerade definieren eine next_morris Funktion wie folgt:

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

Das ist alles !!! Schauen Sie:

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

konnte ich nutzen, um einen Generator zu machen:

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

Verbrauch:

for n in morris_generator(10): 
    print n 

Ergebnisse:

1 
11 
21 
1211 
111221 
312211 
13112221 
+0

vielen Dank. Ich muss wirklich, wirklich, die iterools Bibliothek besser lernen –

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

Zunächst einmal würde ich das Iterator unendlich machen und lassen die Verbraucher entscheiden, wie viel davon er will. Auf diese Weise könnte er entweder jede Morris-Nummer erhalten, die kürzer als x ist oder die ersten x-Zahlen, etc.

Dann gibt es natürlich keine Notwendigkeit, die ganze Liste der vorherigen Morris-Nummern in einer Liste zu speichern, da die Rekursion nur ist n := f(n-1) sowieso.

Schließlich ist die Verwendung von itertools, um ihm einen funktionalen Touch zu geben, immer ein oder zwei Punkte wert;) Ich spalte den Generatorausdruck in mehrere Zeilen, um es ein bisschen einfacher für das Auge zu machen.

Die Haupthässlichkeit in dieser Lösung kommt von der Tatsache, dass len() kann nicht auf einem Iterator aufgerufen werden und gibt uns ein int, wo wir eine str benötigen. Der andere Haken ist die verschachtelte Str. Join), um das Ganze wieder in eine Str zu glätten.

Wenn Sie die Sequenz von beliebigen Zahlen beginnen soll, definieren Sie die Funktion wie folgt aus:

def morris(morris=None): 
    if morris is None: 
     morris = '1' 
[...] 

Wenn Sie um diesen Generator drehen möchten, können Sie es wie folgt schreiben:

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 

Ich bin mir nicht sicher, ob ich die Aufteilung in zwei Funktionen mag, aber dies scheint die beste Lösung zu sein:

Hoffe es gefällt dir!