我正在尝试生成CHAR_LIST
和lower
范围内的动态字符集upper
的每个组合。我在下面粘贴的代码有效,但我觉得它非常低效,我想尽可能快地制作它。
例如,如果我想在“aab”和“zzz”之间生成一个只有小写字母字符的列表,则会输出:['aab', 'aac', 'aad', ..., 'zzy', 'zzz']
如果有什么我不明的请发表评论,我会澄清。谢谢!
我现在正在做什么。
def generate_list(lower, upper):
result = [lower]
while lower != upper:
if CHAR_LIST.index(lower[len(lower)-1:len(lower)]) + 1 < len(CHAR_LIST):
lower = lower[:len(lower)-1] + CHAR_LIST[CHAR_LIST.index(lower[len(lower)-1:len(lower)]) + 1]
else:
new_lower = ""
new_dig = 0
inc_next = True
for i in lower[::-1]:
if i == CHAR_LIST[len(CHAR_LIST)-1] and inc_next:
new_lower += CHAR_LIST[0]
new_dig += 1
else:
if inc_next:
inc_next = False
new_lower += CHAR_LIST[CHAR_LIST.index(i) + 1]
else:
new_lower += i
if new_dig == len(lower):
lower = str(CHAR_LIST[0])*int(len(lower)+1)
else:
lower = new_lower[::-1]
result.append(lower)
return result
编辑:我忘了添加,因为这是挑战的一部分,它还必须计算一个具有不同长度的开始和结束点的列表。例如,它也必须计算“a”和“zzz”之间的列表。对于修订后期感到抱歉,感谢目前为止的创意答案:)
答案 0 :(得分:2)
import itertools
CHAR_LIST = list("abcdefghijklmnopqrstuvwxyz")
def generate_list(lower, upper):
lower, upper = tuple(lower), tuple(upper)
return ["".join(e) for e in itertools.product(CHAR_LIST, repeat=len(lower))
if e >= lower and e <= upper]
print generate_list("aab", "zzz")
答案 1 :(得分:2)
在我看来itertools.product
就是你想要的:
from string import ascii_lowercase
from itertools import product
all_combos = (''.join(x) for x in product(ascii_lowercase,repeat=3))
filtered = (s for s in all_combos if s > 'aaa')
为了与itertools的精彩保持一致,我在这里使用了生成器,但你可以很容易地将第二个生成器用于列表理解以获得列表 - 而且我也相信很容易看到你如何能够转换它进入lower
和upper
边界的函数,对filtered
生成器表达式进行非常简单的修改(已经包含下限;-) ...
答案 2 :(得分:2)
我花了很长时间才了解你的代码是如何工作的,因为你做的工作比你需要的要多得多。这是同一算法的积极“pythonized”版本,我怀疑它比现在的速度快得多:
def generate_strings(value, bound, alpha):
yield value
while value != bound: # run until we have reached bound
for i, c in enumerate(reversed(value)): # loop over the string in reverse
if c != alpha[-1]: # can this character be incremented?
# construct an incremented value
value = value[:-1-i] + alpha[alpha.index(c)+1] + alpha[0]*i
break # exit the for loop
else: # run only if for loop ended without breaking
value = alpha[0]*(len(value) + 1) # make a longer string
yield value
该函数是一个生成器,所以如果你想要一个列表结果,把它传递给列表构造函数,就像在这个例子中输出:
>>> print(list(generate_strings("b", "cc", "abcd")))
['b', 'c', 'd', 'aa', 'ab', 'ac', 'ad', 'ba', 'bb', 'bc', 'bd', 'ca', 'cb', 'cc']
我将字符序列作为函数的参数,而不是使用全局变量。 bound
参数也可以是None
或其他一些无意义的值来获取无限生成器(但不要将其传递给list()
而不缩短它!)。以下是这两个功能的示例:
>>> from itertools import islice
>>> from string import ascii_lowercase
>>>
>>> print(list(islice(generate_strings("xyzzy", None, ascii_lowercase), 5)))
['xyzzy', 'xyzzz', 'xzaaa', 'xzaab', 'xzaac']
如果你是Python的新手,代码中有一些事情可能并不明显。
首先,我在字符串中使用了很多负面索引。这从右侧算起,从-1
开始作为最右边的字符。仅这一点就可以简化你的代码(你有很多x[len(x)-1]
)。
接下来,我使用enumerate
和reversed
内置函数从右到左循环遍历字符串,跟踪我循环的字符数。我认为这与您使用i
和new_dig
值所做的事情有关,但我认为它更清晰。 Python中有许多有用的内置生成器!
最后,我使用break
语句提前退出for
循环,使用else
块来处理我们在没有break
的情况下结束的情况。当我第一次了解它时,循环上的这种else
对我来说似乎毫无用处,但在这样的情况下它确实很方便,其中循环的大部分运行将导致break
声明被击中。