寫這篇教學時正逢解決了一個應該十分簡單,但是搞了我半天的小編程問題。
希望透過這篇教學,讓您了解更多有關列表的知識,並且避免像我一樣傷了半天腦筋才找到答案吧!
核心問題:什麼是合併?
相信我,這個問題遠比它看起來重要。
要知道如何合併列表,首先我們要找出我們需要什麼樣的合併。
如上圖所示,從實用性而言,合併大概可以分成 3 種:子項合併、按序合併、以及直接合併。其中以按序合併最為常用。我們先來學習一下什麼情況下會使用到哪一種合併:
合併類別 | 作用 |
---|---|
子項合併 | 2 張列表的項目屬同一組別,處理每個項目不需要特別照料。 |
按序合併 | 2 張列表的項目是一對對的,需要以一對作為基礎單元處理。例如第一張列表是新郎名稱,第二張列表是新娘名稱。 |
直接合併 | 每張列表可視為更高層的列表的項目。概念與 dataframe 相約。 |
讓我們使用例子逐個介紹如何合併列表吧!
第 1 擊:子項合併
組合條件: 原則上任意 2 個列表皆可進行子項合併。實際用途上,2 個列表的項目是同等和同一個數據類型(data type)最為有用。
list_1 = [1, 2, 3]
list_2 = [4, 5, 6]
list_combined = list_1 + list_2
print(list_combined)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
語法:
list_combined = list_1 + list_2
Python 的編程語法(Syntax)總是出乎意料地簡單。如果我們的目的是直接將 2 個列表視為 1 個處理,那麼就像 1 + 1 = 2,我們直接使用「+」(Addition Operator)便可以把 2 個列表變成 1 個列表了。
這個合併方法適用於將收集到的數據串連起來。
比方說,我們進行一個簡單的普查,透過 5 個調查員派發 100 份問卷,統計受訪者家庭成員數目。我們可能得到的數據是「3、4、2、5、….」,「1、1、3、4、….」,「2、4、3、1、….」,「5、3、2、3、….」的 5 個列表,代表每個調查員收集到的數據。
這時候,我們只要簡單地使用「+」,譬如 list_1 + list_2 + list_3 + list_4 + list_5
,便可以簡單地計算結果的平均值、中位數等。
第 2 擊:按序合併
組合條件: 2 個列表必須有同樣多的項目,即是 len(list_1) == len(list_2)。
list_1 = [1, 2, 3]
list_2 = [4, 5, 6]
list_combined = list(zip(list_1, list_2))
print(list_combined)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
語法:
list_combined = list(zip(list_1, list_2))
這裡我們不得不介紹 zip() 這一個功能。
zip():Python 的拉鍊扣
zip() 就像一個拉鍊扣一樣,把 2 個列表(或更多)按每一項合併起來。
正常情況下,我們這 2 個列表需要有相同數量的項目。那麼如果 2 個列表有不同數目的項目怎麼辦?
這個情況下,zip() 會回傳最少項目的結果。假如 list_1 有 5 個項目,list_2 有 7 個,那麼回傳的結果便只有 5 個項目,對應 list_1 全部項目,和 list_2 頭 5 個項目。
len():如何計算列表有多少項目?
list_1 = [1, 2, 3]
list_2 = [4, 5, 6]
list_3 = [7, 8, 9, 10]
def same_no_of_items(list_1: list, list_2: list):
if len(list_1) == len(list_2):
return True
else:
return False
print(same_no_of_items(list_1, list_2))
print(same_no_of_items(list_1, list_3))
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
也算是一個小小的延伸,就是我們如何檢查 2 個列表有相同數量的項目,以免我們使用 zip() 的時候不小心忽略了一些項目?
len() 這個功能可以告訴我們 1 個列表裡有多少個項目。所以我們只需要檢查 len(list_1) == list(list_2) 的真假值,即可以知道我們能否使用 zip()。
len() 這個語法算是其中一個最普及的編程語法。大部分編程語言裡,檢查數據量都是 len() 這個功能,可以記下來噢。
list(zip()) 回傳的結果
您可能會疑惑,為什麼 zip() 外面我們還要包上 list()?
這是因為 zip() 回傳的是一個 zip object,我們需要透過 list() 這個功能把數據類型轉換成列表,方便處理。
眼利的您會發現回傳的結果是「(1, 4),(2, 5),(3, 6)」。這個結果其實是一個元組的列表(list of tuples),每一個項目皆是擁有 2 個項目的元組。
元組(tuple)的特性是您不能添更多的項目。所以,zip() 保證了您的數據會是同一個維度(dimension)。例如您把 3 個列表 zip() 在一起,維度便是 3 個項目。
List Comprehension 的應用
如果您還沒了解什麼是 list comprehension,記得先看這邊的教學:List Comprehension: Python 的 For Loop 怎樣使用?
花了這麼多口水,當然要介紹一下為什麼按序合併這麼普及。
一個最常見的應用是搭配 list comprehension 使用。假如我們有 2 張列表,而它們的項目是相對應的(即項目 1 對應項目 A、項目 2 對應項目 B),那麼我們可以使用 list comprehension 直接輸出需要相對應的列表結果。
在以下例子,list_1 和 list_2 對應城市與國家的英文名稱。如果我們需要回傳一張含有「城市,國家」的列表怎麼辦?
list_1 = ['Taipei', 'London', 'Tokyo', 'Hong Kong','New York']
list_2 = ['Taiwan', 'United Kingdom', 'Japan', 'Hong Kong', 'United States']
list_combined = [x[0] + ', ' + x[1] for x in list(zip(list_1, list_2))]
print(list_combined)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
語法:
list_combined = [some_functions(x[0], x[1]) for x in list(zip(list_1, list_2))]
沒錯,只要我們使用 list(zip(list_1, list_2))
作為我們 list comprehension 的原始列表,即可簡單地完成我們的任務!
留意我們的回傳項目是 x[0] + ', ' + x[1]
。這是由於 list(zip()) 是一個元組的列表(list of tuples),我們需要以元組的索引(index)來存取元組裡第 N 個項目。
而由於每一個元組的 index = 0 項目是城市,index = 1 項目是國家,所以我們的寫法可以回傳所需的列表。
第 3 擊:直接合併
組合條件: 原則上任意 2 個列表皆可進行直接合併。實際用途上,2 個列表擁有相同數量的項目最為有用。
list_1 = [1, 2, 3]
list_2 = [4, 5, 6]
list_combined = [list_1, list_2]
print(list_combined)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
語法:
list_combined = [list_1, list_2]
最後一個合併的方法本身不太常用,但由於關乎 pandas dataframe 的概念,還是值得一提。
這個合併方法回傳一個列表的列表(list of list)。雖然這個看似複雜,但基本上就是大腸包小腸的概念,列表的項目是另一個列表。
那麼為什麼我們會大費周章去弄這個 Python 的大腸包小腸?
從列表合併製做 pandas dataframe
import pandas as pd
col_headers = ["Name", "Age", "Height"]
person_1 = ["Chan, Tai Man", 23, 176]
person_2 = ["Leung, Woo Pai", 26, 184]
person_3 = ["Ng, Siu Lan", 30, 163]
list_combined = [person_1, person_2, person_3]
df = pd.DataFrame(list_combined, columns=col_headers)
print(df)
註:先按一下綠色按鈕 “Run” 執行代碼,讓您能在 IPython Shell 看到編程結果!
語法:
import pandas as pd df = pd.DataFrame(list_combined, columns=col_headers)
以上的例子是一個簡單製做 pandas dataframe 的方法。我們每一個「小腸」(person_1, person_2, person_3)是一個列表,代表每一個人的數據。
留意「小腸」的數據代表名稱、年齡和身高,我們把這個儲存成 col_headers 列表函數。
我們把小腸組合成大腸,並透過 pd.DataFrame() 的功能轉換成一個簡單的 pandas dataframe。
因此,直接合併這個方法就像是把每一行(row)數據串連一起,成為一個 2D 的數據表。每一行就是一個個體(entity)的不同數據(attribute)。
小延伸:大腸包小腸這個概念也是 CSV 檔案的基本型態噢。
教學完整代碼
最後送給大家這篇教學的 Google Colab 完整代碼。如果您不懂得使用免安裝又好用的 Google Colab Notebook,記得閱讀這篇教學了:新手 1/3:5 分鐘免安裝學習 Python?Google Colab Notebook 幫緊您!
結語
希望您在這篇教學了解到更多有關列表合併的技巧,和 list comprehension 的應用吧!