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

    Python 如何比較 2 張列表 List?教您逐一比較項目 Element-wise

    Python 如何比較 2 張列表 List?教您逐一比較項目 Element-wise
    Share on facebook
    Share on twitter
    Share on linkedin
    Share on whatsapp
    目錄
      Add a header to begin generating the table of contents

      在 Python 我們有時候會需要作出一些比較數據的任務。

      例如我們有 2 組名單(A 和 B),裡面的人名可以出現在 A、B、或者同時出現在 A 及 B,那麼我們可以透過簡單的 Python 編程找出「同時出現在 A 及 B」的群組。

      又例如我們有 2 張列表,一張是數據處理前、一張是處理後,那麼我們透過這些方法亦能找出經過處理的列表成員,甚至還原數據的處理!

      核心問題

      開始編程前,我們先要問一下自己想要解決的問題是什麼。這次我們希望透過比較 2 張列表:

      1. 找出同時存在於兩張列表的項目
      2. 找出兩張列表的不同
      3. 分析兩張列表的分別

      這次教學我們會頻繁使用 Python 獨特的 List Comprehension,如果您不太熟悉記得按一下這篇教學:List Comprehension: Python 的 For Loop 怎樣使用?

      我是廣告 ^o^

      事不宜遲,我們立刻開始學習吧!

      第 1 題:找出同時存在於兩張列表的項目

      list_1 = ['A','B','C','D','E','F','G','H','I'] list_2 = ['G','H','I','J','K','L','M'] intersection = [x for x in list_1 for y in list_2 if x == y] print(intersection)

      註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!

      我們從最簡單的例子開始吧。假如我們有兩張有關英文字母的列表,而第一個列表有 A 至 I、第二個列表有 G 至 M,那麼我們的編程需要回傳 G、H、I 作為同時存於兩張列表的項目。

      留意我們這兩張列表的長度不一,第一張列表比第二張長。

      以下簡單的 list comprehension 可以直接回傳我們所需。我們先稱呼這張回傳的列表為「intersection」。

      我是廣告 ^o^
      intersection = [x for x in list_1 for y in list_2 if x == y]

      這裡略略介紹一下這個寫法的運作方法。List comprehension 基本上就是一個 for loop,而這裡留意我們同時有 for x in list_1for y in list_2 這 2 個 for loop。

      因此,我們在 Loop 到每一個 list_1 的項目(A、B、…)是,檢查一次這個項目是否存在於 list_2 裡(if x == y)。

      其實除了以上寫法之外,我們亦可以這樣寫:

      intersection = [y for x in list_1 for y in list_2 if x == y]

      由於 intersection 的項目必須同時存於 list_1list_2,所以無論我們用 x 或 y 作為回傳的子項目,回傳的 intersection 都是一樣的。

      小插曲:如果我們的列表有重複出現的項目?

      list_1 = ['A','B','C','D','E','F','G','H','H','I'] list_2 = ['G','H','I','J','K','L','M','M'] intersection = [x for x in list_1 for y in list_2 if x == y] print('如果沒有用 set():', intersection) print('如果用 set():', list(set(intersection)))

      註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!

      我是廣告 ^o^

      如果我們在剛才的示範裡加入在同一個列表出現多次的項目(例如 H),那麼以上面的方法計算出來的 intersection 便會出現多次該項目。

      這個用法讓我們容易找出每個同時於兩張列表出現的項目,最高出現的頻率。例如 H 在 list_1 出現 2 次,在 list_2 出現 1 次,那麼算出來的 intersection 便會有 2 個 H。

      但如果我們只需要知道哪些項目同時在兩張列表出現,但我們不太管頻率,那麼我們可以透過這個代碼獲取不重複(unique)的項目:

      list(set(intersection))

      set() 基本上就像是 Excel 移除重複項(Remove Duplicates)的 Python 版。而我們要加以 list(),把這個輸出還原成為一個列表。

      第 2 題:找出兩張列表的不同

      這個比剛才的問題稍為複雜一點,因為我們需要考量的是我們需要什麼樣的不同。

      我是廣告 ^o^
      list_1 = ['A','B','C','D','E','F','G','H','H','I'] list_2 = ['G','H','I','J','K','L','M','M'] difference_in_1_not_in_2 = [x for x in list_1 if x not in list_2] difference_in_2_not_in_1 = [x for x in list_2 if x not in list_1] print('在 list_1 而不在 list_2:', difference_in_1_not_in_2) print('在 list_2 而不在 list_1:', difference_in_2_not_in_1) print('全部不同:', difference_in_1_not_in_2 + difference_in_2_not_in_1)

      註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!

      如果我們比較兩個 list,首先我們需要選擇以哪一個列表作為我們的基準。就如以上例子,我們的 difference_in_1_not_in_2difference_in_2_not_in_1 可是兩個截然不同的回傳!

      如果我們以 list_1 為基準,找出在 list_2 但不在 list_1 裡的項目,語法是:

      difference_in_1_not_in_2 = [x for x in list_1 if x not in list_2]

      那麼,如果我們想要獲取兩個列表不同的所有元素(即是 intersection 的相反),那麼我們可以直接把 difference_in_1_not_in_2difference_in_2_not_in_1 相加。上述編程例子中,difference_all 就是蘊含了這些元素的回傳。

      difference_all = difference_in_1_not_in_2 + difference_in_2_not_in_1

      相加後,由於 difference_in_1_not_in_2difference_in_2_not_in_1 是互相排擠(Mutually Exclusive)的,所以我們不會得到重複的元素。

      我是廣告 ^o^

      當然,正如上面的小插曲提及,如果 list_1list_2 本身有重複出現的項目,而您只需要知道哪些項目重複,您可以使用 list(set(difference_all)) 的方法回傳不重複(unique)的項目。

      第 3 題:分析兩張列表的分別

      最後我們來談談如何簡單分析兩張列表的分別。有時候我們想要還原一些數據處理的結果。我們來先看看一個例子:

      list_1 = ['Chan, Tai Man', 'Chan, Siu Wan', 'Cheung, Ho Man', 'Fung, Ka Yi', 'Lam, Yuen Ho', 'Tse, Lo Si'] list_2 = ['Chan, Tai Man', 'Chan, Siu Wan Ashley', 'Cheung, Ho Man', 'Fung, Ka Yi Karmen', 'Lam, Yuen Ho Ben', 'Tse, Lo Si'] print(list(zip(list_1,list_2)))

      註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!

      譬如這個例子我們有兩張同一個順序的人名,但差別在於 list_1 只有中文名的羅馬拼音,而 list_2 卻多添了英文名稱(如那人有)。

      我們的任務是還原這個數據處理,而我們希望 Python 回傳一個字典(Dictionary),方便我們對應中文名的羅馬拼音與英文名稱。

      我是廣告 ^o^

      留意 zip() 這個功能是把兩張列表的合併成一張,而每一個項目是原來列表的值,以元組(tuple)儲存。前提是我們這兩張列表有一樣數量的項目。

      list_1 = ['Chan, Tai Man', 'Chan, Siu Wan', 'Cheung, Ho Man', 'Fung, Ka Yi', 'Lam, Yuen Ho', 'Tse, Lo Si'] list_2 = ['Chan, Tai Man', 'Chan, Siu Wan Ashley', 'Cheung, Ho Man', 'Fung, Ka Yi Karmen', 'Lam, Yuen Ho Ben', 'Tse, Lo Si'] map_name = {x[0]: x[1].split()[-1] for x in list(zip(list_1,list_2)) if x[0] != x[1]} print(map_name)

      註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!

      這個 map_name 的 List Comprehension 有點複雜。

      我們的字典(Dictionary)的 Key 是 x[0],即是 zip tuple 裡的第一個元素。而我們 zip 的順序是 list_1 先到 list_2,所以第一個元素便是 list_1 的元素,即是沒有英文名稱的元素。

      字典的 Value 是 x[1].split()[-1]x[1] 是我們含有英文名稱的元素(來自 list_2),我們通過提取名稱最後一個字(.split()[-1])獲取對應該人的英文名稱。

      我是廣告 ^o^

      但是,對於沒有英文名稱的人,我們不想把他們加入到字典裡,所以我們最後加入 if x[0] != x[1] 的語法,確保回傳的字典只會是有英文名稱的人。

      現在我們可以拿著 map_name 去告訴別人我們的英文名稱是什麼了!

      這個語法的偽代碼(pseudo-code)如下:

      {x[0]: some_function(x[1]) for x in list(zip(list_1, list_2)) if x[0] != x[1]}

      教學完整代碼

      最後送給大家這篇教學的 Google Colab 完整代碼。如果您不懂得使用免安裝又好用的 Google Colab Notebook,記得閱讀這篇教學了:新手 1/3:5 分鐘免安裝學習 Python?Google Colab Notebook 幫緊您!

      結語

      當然,比較兩張列表的方法有許多,我們不能盡錄,但希望以上例子讓您學會更多有關 List Comprehension 的多變和強大的用途!

      我是廣告 ^o^

      人氣文章

      快讓我學更多

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