目錄
    Add a header to begin generating the table of contents

    List Comprehension: Python 的 For Loop 怎樣使用?

    List Comprehension: Python 的 For Loop 怎樣使用?
    Share on facebook
    Share on twitter
    Share on linkedin
    Share on whatsapp
    目錄
      Add a header to begin generating the table of contents

      要數 Python 其中一個最吸引我的地方,就是能夠將編程的 For Loop 極度簡化成一行淺白的 Code。對於十分懶惰的我,無疑是個解脫。這個特別的編程語法名為 List Comprehension。

      簡單而言,List Comprehension 是一個重整列表的方法。透過原來的列表,加以一些簡單的處理,去製做一個新的列表。在大部分其他的編程語言,例如 C、Java、VB 等,通常我們需要明確地 (Explicitly) 寫出 For Loop ,但在 Python 編程裡,可以透過隱密的 (Implicit)語法達至相同效果。

      除了簡單處理以外,List Comprehension 亦能用以製做字典(Dictionary)、元組(Tuple)等可疊代(iterable)的資料結構,又可以自訂功能,用途可能遠比您想像大!

      列表 List Comprehension

      列表(List)

      最原始的 List Comprehension 例子是將一個 List 轉換成另外一個 List。編程語法是:

      output_list = [func(x) for x in input_list]

      我是廣告 ^o^

      我們先看看以下例子:

      my_list = ['士多', '啤梨', '啤梨', '蘋果', '橙'] output = ['生果: ' + x for x in my_list] print(output)

      在這個例子,我們簡單地在每款生果上標記「生果」。對比起傳統的 For Loop,List Comprehension 的語法:

      output = ['生果: ' + x for x in my_list]

      更加直接了當。語法的括號代表我們輸出成 List,而 For each 的語法則跟隨每個 element 之後,代表我們隱密地(Implicitly)使用了 For loop。

      字典(Dictionary)

      另外比較常見的 List Comprehension 可以用於製作字典。字典(Dictionary)多數用作一些 item-attribute 的情況,例如 key 是一班學生,attribute 是他們的身高、體重、血型等。編程語法是:

      我是廣告 ^o^

      output_dict = {key(x): item(x) for x in input_list}

      我們看看以下例子:

      from pprint import pprint my_list = ['士多', '啤梨', '啤梨', '蘋果', '橙'] output = {x: {'第一個字': x[0], '類別': '生果'} for x in my_list} pprint(output, width=1)

      在這個例子,我們製做的字典輸出 2 個屬性:生果的第一個字(例如:蘋果 -> 蘋)、以及類別(生果)。

      留意 output 只有 4 個 item,因為字典只能接受獨特(Unique)的 key,所以只有 1 個啤梨而非 2 個啤梨。

      元組(Tuple)

      元組(Tuple)則用於您想限制有多少 item 的情況,例如 DSE 成績只能是(5**,5*,5,4,3,2,1,U)的 8 個可能性。 編程語法是:

      我是廣告 ^o^

      output_tuple = tuple([func(x) for x in input_list])

      留意我們需要先製做列表,再以 tuple() 轉換成元組。我們看看以下例子:

      my_list = ['士多', '啤梨', '啤梨', '蘋果', '橙'] output = tuple([len(x) for x in my_list]) print(output)

      透過 List Comprehension,我們輕鬆地將每款生果的名稱字數(例如蘋果 -> 2)輸出成為列表,再轉換成元組。

      字典(Dict Comprehension)

      另一個非常好用的型態是 Dictionary Comprehension,就是我們的 input 是字典而非列表。編程語法是:

      output = {key(k): item(v) for k, v in input_dict.items()}

      我是廣告 ^o^

      特別是處理 JSON 類的數據時(例如包含學生的身高、體重、血型等許多 attribute),我們只需要抽取數據裡的其中一項(attribute), Dict Comprehension 就會非常好使。

      我們看看以下例子:

      from pprint import pprint my_dict = { '啤梨': {'第一個字': '啤', '類別': '生果'}, '士多': {'第一個字': '士', '類別': '生果'}, '橙': {'第一個字': '橙', '類別': '生果'}, '蘋果': {'第一個字': '蘋', '類別': '生果'} } output = {k: v['第一個字'] for k, v in my_dict.items()} pprint(output, width=1)

      我們使用先前的例子生成的字典,抽取裡面的其中一項。可見 Dict Comprehension 是一種壓縮(Compress)字典的好方法。

      條件式 List Comp(If-else)

      List Comprehension 更進一層樓的用法是加入條件式處理。這個使 List Comprehension 涵蓋更為廣泛的應用。

      當中可以分為 2 種用法:篩選式用途(Filtering),以及辨別式用途(Distinguishing)。

      我是廣告 ^o^

      篩選式用途(If)

      List Comprehension 可以用於篩選列表/字典裡的項目。編程語法是:

      output = [func(x) for x in input_list if cond(x)]

      或者

      output = {key(k): item(v) for k, v in input_dict.items() if cond(k, v)}

      我們來看看以下 2 個例子:

      我是廣告 ^o^
      my_list = ['士多', '啤梨', '啤梨', '蘋果', '橙'] output = [x for x in my_list if len(x) == 2] print(output) from pprint import pprint my_dict = { '啤梨': {'第一個字': '啤', '類別': '生果'}, '士多': {'第一個字': '士', '類別': '生果'}, '橙': {'第一個字': '橙', '類別': '生果'}, '蘋果': {'第一個字': '蘋', '類別': '生果'} } output = {k: v for k, v in my_dict.items() if v['第一個字'] == '啤'} pprint(output, width=1)

      在第 1 個例子,我們在列表選取名字有 2 個字的生果,所以輸出的列表沒有了「橙」。在第 2 個例子,我們在字典選取第一個字為「啤」的生果,所以輸出的字典只有「啤梨」和其相應的屬性(Attribute)。

      留意這個用法跟 SQL 裡面的 “SELECT * WHERE COND” 和 Excel 的 =IF() 基本相同。於數據提取(Data Extraction)的角度而言,篩選式的 List Comprehension 是非常強大的工具!

      辨別式用途(If-else)

      除了篩選式用途,List comprehension 的條件式語法亦能做到辨別式用途,即是透過辨別 element 的特性而輸出不同結果。編程語法是:

      output = [func1(x) if cond(x) else func2(x) for x in input_list]

      或者

      我是廣告 ^o^

      output = {(key1(k) if cond(k, v) else key2(k)): (item1(v) if cond(k, v) else item2(v)) for k, v in input_dict.items()}

      這真是一個很長的語法!我們來看看實例:

      my_list = ['士多', '啤梨', '啤梨', '蘋果', '橙'] output = ['一: ' + x if len(x) == 1 else '二: ' + x for x in my_list] print(output)

      在第 1 個例子,我們透過辨別式 List Comprehension 把生果的字數串連到生果名字上。第 2 個例子較為複雜:

      • 以條件式在 key 註明生果的字數串連到生果名字上
      • 以條件式在 value 選取生果的項目(Attribute):如果生果名字只有 1 個字,選取「類別」,否則選取「第一個字」

      在數據轉型(Data Transformation)裡,辨別式的 List Comprehension 是專家。例如我們提取有關學生 JSON 數據時,想透過身高做一個簡單的分類(’高‘ if height > 170 else ‘矮'),那麼字典的 Dict Comprehension 就會十分適合。

      自訂功能

      如果您需要十分複雜的數據處理,那麼 List Comprehension 仍然能夠符合您的要求!

      我是廣告 ^o^

      還記得我們介紹 List Comprehension ,括號裡的是 Func(x) ?沒錯!我們可以使用自訂的功能(Custom Function)製成新的列表。(進階用家:這個類似於其他編程語言的 Lambda function)

      我們來看看以下例子。

      def BMI(v): return round(v['體重'] / (v['身高'] ** 2), ndigits=2) from pprint import pprint my_dict = { '碳治郎': {'身高': 1.65, '體重': 56}, '杏壽郎': {'身高': 1.77, '體重': 72}, '甘露寺': {'身高': 1.67, '體重': 56}, '蝴蝶忍': {'身高': 1.51, '體重': 37}, } output = {k: BMI(v) for k, v in my_dict.items()} pprint(output, width=1)

      透過定義 BMI() 一功能,我們成功地計算了鬼滅每個人的 BMI,亦證明了鬼滅的人物設定頗符合身高體重。當然,除了簡單的加減乘除以外,我們亦可以透過自訂功能使用 For Loop 裡的 For Loop 計算 Fibonacci Sequence 等。

      自訂功能的編程寫法亦合乎「簡化編程」的原則:我們可以分開 Loop 以及 Lambda function,使我們更容易除錯排難。

      List Comprehension 的限制

      當然,List Comprehension 亦不能完全取代原始 For Loop 。有時候,我們的 For Loop logic 需要更新幾個不同的變數時,即使使用了自訂功能的 List Comprehension 亦會使編程變得難以理解,甚至不能簡單地以 List Comprehension 寫出。

      我是廣告 ^o^

      這類複雜的情況,我們便需要根據問題的需要,先想想有沒有辦法簡化程序。如果確實沒有簡化的餘地,那麼使用原始 For Loop 亦不失為一個好方法。最重要的,是想像自己 6 個月後再看一遍,是否能夠明白這個 List Comprehension。如果不能,那麼原始 For Loop 可能是您最好的答案。

      您還想到其他 List Comprehension 的用途嗎?歡迎到「聯絡我們」告訴我們您的主意/問題!

      人氣文章

      快讓我學更多

      small_c_popup.png
      想學習 Python 嗎?
      快來訂閱我們的電子報!