2

我正在尝试在 和 范围内生成动态字符集的每个CHAR_LIST组合。我在下面粘贴的代码有效,但我觉得它的效率非常低,我想尽可能快。lowerupper

例如,如果我想在“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”之间的列表。抱歉修改晚了,感谢到目前为止的创造性答案:)

4

3 回答 3

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")
于 2013-01-31T01:26:16.233 回答
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 的出色保持一致,我在这里使用了生成器,但是您可以轻松地将第二个生成器转换为列表推导式以获取列表——而且我也相信很容易看出如何将其转换为函数withlowerupperbounds 对生成器表达式进行非常简单的修改filtered(下限已经包括在内 ;-) ...

于 2013-01-31T01:26:25.527 回答
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])。

接下来,我使用enumeratereversed内置函数从右到左循环字符串,跟踪我循环了多少个字符。我认为这是关于您对自己的价值观所做的事情inew_dig但我认为这要清楚得多。Python中有很多有用的内置生成器!

最后,我使用了一个break语句来提前退出for循环,用一个块来处理我们没有ingelse就结束了的情况。当我第一次了解它时,这种循环对我来说似乎没用,但在这种情况下它确实很方便,循环的大部分运行都会导致break语句被命中。elsebreak

于 2013-01-31T05:00:58.073 回答