python list comprehension double for

python list comprehension double for

1
2
3
4
vec = [[1,2,3], [4,5,6], [7,8,9]]
print [num for elem in vec for num in elem]      <----- this

>>> [1, 2, 3, 4, 5, 6, 7, 8, 9]

这是在骗我。我知道Elem是来自for elem in vic的列表中的列表我不太了解numfor num in elem在开头和结尾的用法。

Python如何解释这个问题?它的顺序是什么?


让我们把它分解。

简单的列表理解:

1
[x for x in collection]

如果我们把它分成几个部分,这很容易理解:[A for B in C]

  • A是结果列表中的项目。
  • B是集合C中的每个项目。
  • C是集合本身。

这样,我们可以写:

1
[x.lower() for x in words]

以便将列表中的所有单词转换为小写。

当我们用类似这样的另一个列表来复杂化这一点时:

1
[x for y in collection for x in y] # [A for B in C for D in E]

在这里,发生了一些特殊的事情。我们希望最终的清单包括A项,A项在B项中,因此我们必须告诉清单理解。

  • A是结果列表中的项目。
  • B是集合C中的每个项目。
  • C是集合本身
  • D是集合E中的每一项(在这种情况下,也是A中的每一项)
  • E是另一个集合(在本例中,B)

此逻辑类似于正常for循环:

1
2
3
for y in collection:     #      for B in C:
    for x in y:          #          for D in E: (in this case: for A in B)
        # receive x      #              # receive A

为了扩展这一点,并给出一个很好的例子+解释,假设有一列火车。

火车引擎(前部)总是在那里(列表理解的结果)

那么,有多少节车厢,每节车厢的形式是:for x in y

列表理解可能如下所示:

1
[z for b in a for c in b for d in c ... for z in y]

这就像是有一个规则的for循环:

1
2
3
4
5
6
for b in a:
    for c in b:
        for d in c:
            ...
                for z in y:
                    # have z

换言之,在列表理解中,您不需要沿着一行缩进,而是在末尾添加下一个循环。

回到火车类比:

EngineCarCarCar……Tail

尾巴是什么?在清单理解中,尾部是一个特殊的东西。您不需要一个,但是如果您有一个尾部,尾部是一个条件,请看这个例子:

1
[line for line in file if not line.startswith('#')]

只要文件中的每一行没有以hashtag开头(#),其他行就被跳过。

使用列车"尾部"的诀窍是,在您拥有所有循环的最终"引擎"或"结果"的同时,检查其是否正确/错误,上面规则for循环中的示例如下:

1
2
3
for line in file:
    if not line.startswith('#'):
        # have line

请注意:尽管在我对火车的类比中,在火车的尾部只有一个"尾部",但条件或"尾部"可以在每一个"车厢"或回路之后…

例如:

1
2
3
>>> z = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> [x for y in z if sum(y)>10 for x in y if x < 10]
[5, 6, 7, 8, 9]

在常规for循环中:

1
2
3
4
5
6
7
8
9
10
11
>>> for y in z:
    if sum(y)>10:
        for x in y:
            if x < 10:
                print x

5
6
7
8
9


从列表理解文档中:

When a list comprehension is supplied, it consists of a single expression followed by at least one for clause and zero or more for or if clauses. In this case, the elements of the new list are those that would be produced by considering each of the for or if clauses a block, nesting from left to right, and evaluating the expression to produce a list element each time the innermost block is reached.

换句话说,假设for循环是嵌套的。从左到右阅读您的列表理解可以嵌套为:

1
2
3
for elem in vec:
    for num in elem:
        num           # the *single expression* from the spec

其中,列表理解将使用最后一个最里面的块作为结果列表的值。


您的代码等于:

1
2
3
4
temp = []
for elem in vec:
    for num in elem:
        temp.append(num)