簡體   English   中英

理解列表理解,以便在python中展平列表列表

[英]understanding list comprehension for flattening list of lists in python

我發現這種理解非常適用於展平列表列表:

>>> list_of_lists = [(1,2,3),(2,3,4),(3,4,5)]
>>> [item for sublist in list_of_lists for item in sublist]
[1, 2, 3, 2, 3, 4, 3, 4, 5]

我比使用itertools.chain()更喜歡這個,但我無法理解它。 我試過用括號括起來的部分,看看我是否可以減少復雜性,但現在我只是更加困惑:

>>> [(item for sublist in list_of_lists) for item in sublist]
[<generator object <genexpr> at 0x7ff919fdfd20>, <generator object <genexpr> at 0x7ff919fdfd70>, <generator object <genexpr> at 0x7ff919fdfdc0>]

>>> [item for sublist in (list_of_lists for item in sublist)]
[5, 5, 5]

我覺得我很難理解,因為我不太明白發電機是如何工作的......我的意思是,我以為我做了,但現在我真的很懷疑。 就像我說的,我喜歡這個成語是多么緊湊,這正是我需要的,但我不願意使用我不理解的代碼。

誰能解釋一下究竟發生了什么?

列表理解

當我第一次開始列表理解時,我讀到的就像英語句子一樣,我能夠很容易地理解它們。 例如,

[item for sublist in list_of_lists for item in sublist]

可以像

for each sublist in list_of_lists and for each item in sublist add item

此外,過濾部分可以讀作

for each sublist in list_of_lists and for each item in sublist add item only if it is valid

而相應的理解將是

[item for sublist in list_of_lists for item in sublist if valid(item)]

發電機

它們就像地雷一樣,只有在用next協議調用時才會觸發。 它們類似於函數,但是直到引發異常或函數結束,它們才會耗盡,並且可以一次又一次地調用它們。 重要的是,它們保留了先前調用和當前調用之間的狀態。

生成器和函數之間的區別在於,生成器使用yield關鍵字將值返回給調用者。 在生成器表達式的情況下,它們類似於列表推導,第一個表達式是實際值“被屈服”。

有了這個基本的理解,如果我們看一下你在問題中的表達方式,

[(item for sublist in list_of_lists) for item in sublist]

您正在將列表理解與生成器表達式混合使用。 這將是這樣的

for each item in sublist add a generator expression which is defined as, for every sublist in list_of_lists yield item

這不是你心中的想法。 並且由於不迭代生成器表達式,因此生成器表達式對象將按原樣添加到列表中。 由於在沒有使用下一個協議調用的情況下不會對它們進行評估,因此它們不會產生任何錯誤(如果有的話,除非它們有語法錯誤)。 在這種情況下,它將產生運行時錯誤,因為尚未定義sublist

另外,在最后一種情況下,

[item for sublist in (list_of_lists for item in sublist)]
for each sublist in the generator expression, add item and the generator expression is defined as for each item in sublist yield list_of_lists.

for循環將迭代任何可迭代的下一個協議。 因此,發電機表達式進行評估, item將始終處於的迭代的最后一個元素sublist和您添加的列表。 這也會產生運行時錯誤,因為尚未定義子列表。

從左到右閱讀for循環,就好像它們是嵌套的一樣。 左邊的表達式是在最終列表中生成每個值的表達式:

for sublist in list_of_lists:
    for item in sublist:
        item  # added to the list

if測試過濾使用的元素,列表推導也支持; 這些也可以看作是嵌套語句,與for循環相同。

通過添加括號,您更改了表達式; 括號中的所有內容現在都是要添加的左側表達式:

for item in sublist:
    (item for sublist in list_of_lists)  # added to the list

像這樣的for循環是生成器表達式。 它的工作方式與列表理解完全相同,只是它不構建列表。 而是根據需要生成元素。 您可以向生成器表達式詢問下一個值,然后是下一個值,等等。

在這種情況下,必須有一個預先存在的sublist對象才能使其工作; 畢竟,外部循環不再是list_of_lists了。

您的最后一次嘗試轉換為:

for sublist in (list_of_lists for item in sublist):
    item  # aded to the list

這里list_of_lists是生成器表達式中的循環元素,循環遍歷for item in sublist 同樣, sublist必須已經存在才能使其工作。 然后循環將預先存在的item到最終列表輸出中。

在您的情況下,顯然sublist是一個包含3個項目的列表; 你的最終名單產生了3個元素。 item綁定為5 ,因此你的輸出中有3次5

列表理解的工作方式如下:

[<what i want> <for loops in the order you'd write them naturally>]

在這種情況下, <what I want>是每個sublist每個item 要獲取這些項目,只需循環顯示原始列表中的子列表,然后保存/生成子列表中的每個項目。 因此,列表推導中for循環的順序與您未使用列表推導時使用的順序相同。 唯一令人困惑的部分是<what I want>首先出現,而不是最后一個循環體內。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM