2013-07-15 37 views
31
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 list comprehension double for

python如何解释这个?
它看起来的顺序是什么?

+0

[在列表综合双迭代](可能重复http://stackoverflow.com/questions/1198777/double - 在列表中理解) –

+3

这不是一个很好的@Inbar的愚蠢目标,因为它没有解释Python如何解释嵌套循环的顺序。 –

+0

相关/可能的欺骗:[嵌套列表解析](http://stackoverflow.com/a/11934483) –

回答

60

让我们分解它。

一个简单的列表理解:

[x for x in collection] 

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

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

这样,一个可以写:

[x.lower() for x in words] 

为了所有单词转换列表中的小写。


这是当我们像这样另一个列表复杂的:

[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 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

列表理解可以是这样的:

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

这将是就像这个普通的for循环:

for b in a: 
    for c in b: 
     for d in c: 
      ... 
       for z in y: 
        # have z 

换句话说,不是在列表中理解,而是在列表理解中添加下一个循环。

要回去的火车的比喻:

Engine - Car - Car - Car ... Tail

什么尾巴?尾巴是列表理解中的特殊事物。你并不需要一个,但如果你有一条尾巴,尾巴是一个条件,看看下面这个例子:

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

这只要给你一个文件中的每一行线没” t以标签(#)开头,其他人只是跳过。

使用列车“尾巴”的技巧是,在你有来自所有循环的最终'引擎'或'结果'的同时检查是否为真/假,以上示例为定期for循环应该是这样的:

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

请注意:虽然在我的一列火车的比喻,只有一个“尾巴”在列车的末尾,条件或“尾巴”可以'汽车'或循环...

例如:

>>> 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循环:

>>> for y in z: 
    if sum(y)>10: 
     for x in y: 
      if x < 10: 
       print x 

5 
6 
7 
8 
9 
+0

你的答案意味着你只能在列表理解结束时使用'if'语句。这是**不是**。你可以在你的列表解析中使用*任何*级别的if语句,甚至可以放几个(尽管在你意识到它们被嵌套之前看起来有点无意义)。你不能使用'if'作为* first *项目,它必须是'for'循环。 –

+2

你说得对,我并不是想暗示这一点,我会更加清楚。 –

+0

我必须说你的解释过于复杂。特别是当你开始在'C中为C中的D代替B中的A时,B代入C中的B代替B中的A时,将'E中的D'放弃。 –

6

您的代码等于:

temp = [] 
for elem in vec: 
    for num in elem: 
     temp.append(num) 
+4

请注意,'for'语句按照他们将被编写的相同顺序写入列表理解中如上所述定期写入'for'循环。 – kindall

7

list comprehension documentation

当提供一个列表理解,它由一个单一的表达,随后在至少一个for子句和零个或多个for的或if条款。在这种情况下,新列表的元素是那些通过考虑每个for或if子句产生的元素,一个块从左到右嵌套,并且每次到达最内层块时评估表达式以产生列表元素。

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

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

在列表解析会使用最后,最里面块作为结果列表中的值。

相关问题