我正在编写一个函数来增加一个3个字母(a-z)的字符串。例如:
输入: aaa
输出:baa
输入: zba
输出:aca
所以订单如下
aaa
baa
...
zaa
aba
bba
cba
...
zba
aca
bca
cca
...
zca
ada
...
zzz
aaa
我编写了以下函数next_code()
并且它有效,但我想知道是否有更优雅的方法来实现它而不是循环遍历字符串中的单个字母:
# 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'))
答案 0 :(得分:6)
只使用itertools产品
>>> 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'
...
我可能会这样做
如果你想回到'aaa'在结束之后你可以使用itertools.cycle
strings = itertools.cycle(itertools.product(*[ascii_lowercase]*3))
答案 1 :(得分:2)
你可以大量简化循环:
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)
如果目标是逐个生成所有值,从'aaa'
开始,itertools.product
可用于生成生成器:
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)
或者你可以根据需要调用它来获取序列中的下一个代码而不将其用作迭代器:
nextcode = allcodes().__next__ # .next on Py2
如果生成器应该是无限的(因此它从zzz
包裹到aaa
),只需将allcodes
更改为:
# 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
或更高的内存成本,但更简单:
from itertools import cycle
def allcodes():
return cycle(map(''.join, map(reversed, product(string.ascii_lowercase, repeat=3))))