2016-06-21 20 views
0

Ich schreibe eine Funktion, um eine 3-Buchstaben (a-z) Zeichenfolge zu inkrementieren. Zum Beispiel:
Eingang: aaa
Ausgang: baaInkrementieren Zeichenfolge in Python

Eingang: ZBA
Ausgang: aca

So wird die Reihenfolge wie folgt

aaa 
baa 
... 
zaa 
aba 
bba 
cba 
... 
zba 
aca 
bca 
cca 
... 
zca 
ada 
... 
zzz 
aaa 

Ich schrieb folgendes f Salbung next_code() und es funktioniert, aber ich frage mich, ob es eine elegantere Weg ist, es zu implementieren und nicht durch einzelne Buchstaben im String Looping:

# 0 = a; 25 = z 
def digit_to_char(digit): 
    return chr(ord('a') + digit) 

# a = 0; z = 25 
def char_to_digit(char): 
    return ord(char)-ord('a') 

def next_code(code): 
    # if used up all codes, loop from start 
    if code == 'zzz': 
     return next_code('aaa') 
    else: 
     code = list(code) 
     # loop over letters and see which one we can increment 
     for (i, letter) in enumerate(code): 
      if letter == 'z': 
       # go on to the next letter 
       code[i] = 'a' 
       continue 
      else: 
       # increment letter 
       code[i] = digit_to_char(char_to_digit(letter) + 1) 
       return ("".join(code)) 
       break 



print (next_code('aab')) 

Antwort

2

Sie können die Schleife viel vereinfachen:

def next_code(code): 
    code = list(code) 
    for i, let in enumerate(code): 
     if let != 'z': 
      code[i] = chr(ord(let) + 1) 
      break 
     code[i] = 'a' 
    return ''.join(code) 

Wenn das Ziel nur ist, um alle Werte eins nach dem anderen zu produzieren, mit 'aaa' starten, itertools.product verwendet werden kann, einen Generator zu machen:

from future_builtins import map # Only on Python 2 
from itertools import product 

def allcodes(): 
    # You want the left side to vary faster, so reverse before joining 
    return map(''.join, map(reversed, product(string.ascii_lowercase, repeat=3))) 

for code in allcodes(): 
    print(code) 

Oder Sie machen es eine Funktion, die Sie aufrufen, um den nächsten Code in der Sequenz zu erhalten, ohne es als Iterator zu verwenden:

nextcode = allcodes().__next__ # .next on Py2 

Und wenn der Generator unendlich sein sollte (so es zzz-aaa Wraps), nur allcodes entweder ändern:

# Avoid cycle if storing all 26**3 codes in memory is a bad idea 
def allcodes(): 
    while True: 
     yield from map(''.join, map(reversed, product(string.ascii_lowercase, repeat=3))) 
     # On Py2, change yield from line to: 
     # for code in map(''.join, map(reversed, product(string.ascii_lowercase, repeat=3))): yield code 

oder bei höheren Speicherkosten aber eine größere Einfachheit:

from itertools import cycle 

def allcodes(): 
    return cycle(map(''.join, map(reversed, product(string.ascii_lowercase, repeat=3)))) 
+0

wow tolle Antwort ... Sie abgedeckt so viele Basen für diesen Kerl +1 von mir :) –

+0

@JoranBeasley: TIMTOWTDI? :-) Und ich finde sie alle gerne. Ich habe mit Perl angefangen. – ShadowRanger

+0

TSBO - APOO - OWTDI: P (lol) –

6

nur itertools Produkt

>>> import itertools 
>>> from string import ascii_lowercase 
>>> strings = itertools.product(*[ascii_lowercase]*3) 
>>> "".join(next(strings,"No More Combos...")) 
'aaa' 
>>> "".join(next(strings,"No More Combos...")) 
'aab' 
>>> "".join(next(strings,"No More Combos...")) 
'aac' 
... 

ist verwenden, wie ich würde wahrscheinlich tun es

wenn Sie fahren wollen zurück zu ‚aaa‘ nach dem Ende können Sie itertools.cycle nur

strings = itertools.cycle(itertools.product(*[ascii_lowercase]*3)) 
verwenden
+0

Danke, +1 für eine sehr saubere Lösung. Leider unterstützt keine Eingabe (um den nächsten Wert basierend darauf zu erhalten), sollte aber nicht schwer hinzuzufügen sein. –