理解并简化这条线

Understanding and simplifying this line

我找到了这个用于查找给定长度的字母表的所有字符串的示例。

for i in range(length):
    result = [str(x)+str(y) for x in alphabet for y in result or ['']]

我试图了解它是如何工作的,如果它是用 for 循环实现的,它会是什么样子——我所有的简化它的尝试都变得非常混乱,并因无限循环而崩溃……而这个每次都有效时间.


示例:

def allstrings(alphabet, length):
    """Find the list of all strings of 'alphabet' of length 'length'"""

    alphabet = list(alphabet)

    result = []

    for i in range(length):
        result = [str(x)+str(y) for x in alphabet for y in result or ['']]

    return result

# will return ['aa', 'ab', 'ba', 'bb']
print(allstrings({'a', 'b'}, 2)))

# will return ['000', '001', '010', '011', '100', '101', '110', '111']
print(allstrings({'0', '1'}, 4)))

代码修改自:http://code.activestate.com/recipes/425303-generating-all-strings-of-some-length-of-a-given-a/

>>> alphabet="abcd"
>>> list(itertools.permutations(alphabet,3))

应该负责查找字母表(字长 3)的所有排列

基本上,您使用的是所谓的列表推导式,它本质上是 returns 列表的反向 for 循环。使用这种技术,您可以迭代给定长度的给定字母,将字符串连接在一起。

简而言之,这相当于您的代码,因为我还没有看到其他人为您提供它。我确实推荐使用像 Joran Beasley 写的那样的 itertools,因为它们速度更快,而且它们的声明也更加清晰和简单。

def permute(alphabet):
    result = []
    for x in alphabet:
        for y in alphabet:
            result.append(str(x)+str(y))
    return result

IDLE 输出为:

>>> alphabet = ["a", "b", "c"]
>>> r = permute(alphabet)
>>> r
['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc']

但是,这种方法使定义所需长度变得更加困难。要达到这种效果,您必须执行以下操作:

def permute(original, permutated):
    result = []
    for x in alphabet:
        for y in permutated or [""]:
            result.append(str(x)+str(y))
    return result

def helper(alphabet, length):
    res = []
    for i in range(length):
        res = permute(alphabet, res)
    return res

现在的输出如下:

>>> h = helper(alphabet, 2)
>>> h
['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc']
>>> h = helper(alphabet, 3)
>>> h
['aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc', 'baa', 'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bcc', 'caa', 'cab', 'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']

你能弄清楚发生了什么吗?或者我应该写一个解释。 (但请先努力)。

只是一个双列表理解,如果你这样想就简单多了:

print [a for a in "abc"] # ['a', 'b', 'c']

如果你在其中做两件 for ... in ... 事情,它就像一个嵌套循环;

result = [XXX for a in as for b in bs for c in cs...]

其中 XXXabc、...您使用的各种容器的元素的函数(这部分在'in's) 转换为:

result = []
for a in as:
  for b in bs:
    for c in cs:
      ...#however much nesting you want
      result.append(XXX)

你可以通过交换顺序来看到这一点:

print [a+b for a in "ab" for b in "xy"] # ax ay bx by
print [a+b for b in "xy" for a in "ab"] # ax bx ay by

现在为您提供实际示例:

for i in range(length):
  result = [str(x)+str(y) for x in alphabet for y in result or ['']]


this just follows the same rules as above, but there is one extra little hitch; the `result or ['']` part. It is possible to have `if ... else ...` style constructs in list comprehensions, though you'll probably want to avoid those for now. That is *not* what's happening here though, the code is a little clearer if you change it to this:

for i in range(length):
  result = [str(x)+str(y) for x in alphabet for y in (result or [''])]

本质上,它利用了 [](即空列表)在转换为 bool* 时算作 False 的事实。所以如果列表为空,它将被替换为 ['']。这是必要的原因是,如果结果是空字符串(或数组),则不会通过 for 循环进行迭代 - 包含空字符串的数组工作正常,因为它有一个元素(一个空字符串)。

这是 bool 的大小写,因为使用了 or 运算符。如果你这样做:

a = var1 or var2

然后,a 将是 var1 - 除非它是算作 False;

的对象之一
print False or "other" # other
print None or "other" # other
print True or "other" # True
print "" or "other" # other
print " " or "other" # ' '
print 0 or "other" # other
print 1 or "other" # 1
print 134513456 or "other" # 134513456
print [] or "other" # other
print [0] or "other" # [0]
...

我相信你明白了。

您所拥有的代码的另一个可能令人困惑的方面是它设置变量 result,同时在列表理解中使用相同的变量。这没关系,因为在列表理解完成之前不会设置变量。

所以要使用普通循环将其转换成某种东西:

for i in range(length):
  result = [str(x)+str(y) for x in alphabet for y in result or ['']]


result = [""]
for i in range(length):
  temporary_result = []
  for original_sequence in result:
    for new_letter in alphabet:
      temporary_result.append(original_sequence + new_letter)
  result = temporary_result[:]

其中 [:] 是一种复制数组的简单方法。