2013-07-15 36 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 

在列表解析會使用最後,最裏面塊作爲結果列表中的值。

相關問題