【Python基礎教學】資料型態函數及方法(下)【part-9】 === 目錄(Table of Contents) [TOC] --- 哈囉大家好,很感謝你點進本文章,我是一名高中生,是電腦社社團的社長,由於我並不是 Python 這方面非常精通的專家,所以若文章有些錯誤請見諒,也可向我指正錯誤。另外本文章的用意是作為電腦社社團的教材使用而編寫的。 上次我們講到了 Number、String 更深入的用法,以及介紹他們特有的函數及方法。本篇教學【part 9】繼續延續上篇尚未講完的資料型態:list、tuple、set。 列表(List) --- 列表,也可稱為串列(List),說到列表,就讓我們來談及一個概念:序列(Sequence) 序列,是 Python 中最基本的資料結構,是 Python 中的一種內建型態(built-in type)。 > 內建型態就是建構在 Python Interpreter(Python 直譯器)裡面的型態 簡單來說,內建型態就是在 Python 中不需要額外安裝模組或套件,就能直接使用的資料型態,如同:Number、String 等等。 序列中的每個值都具有對應的位置值,稱為索引(index)。所有索引的開頭都預設為 0 開始,慢慢疊加上去,如:0、1、2、3 等。 在 Python 中,內建 6 個序列的內建型態,而最常見的就是列表(list)跟元組(tuple)。 ### 定義(definition) --- 列表(list)是一種常見的內建資料結構。列表是一種有序的集合,可以包含不同資料型態的元素(element)。列表的元素是可變的(mutable),這表示你可以任意修改列表之內容,例如增加、刪除或修改元素。列表使用中括號 [] 定義,元素之間以逗號分隔。 以左右兩個中括號 [],括起來,裡面可以放入任意不同的資料型態,不受限,也可以在列表裡面放入一個列表,這稱為二維列表。 不過需要注意的是,在列表內每一個資料型態(元素)之間需要以逗號作為分隔,範例如下所示: ```python= ['s', 1234, 0.234324, [1,2,3,4,5,6]] # 這是一個列表 list1 = [1,2,3,4] # 將列表存入變數 list1 當中 ``` 註:不建議使用 list 作為變數名稱,因為 list() 是內建函數,能使資料型態變成列表(顯式轉換),如果同名的話可能導致函數失效。 ### 運算(operation) --- | statement | 結果 | 描述 | | -------- | -------- | -------- | | len([1, 2, 3]) | 3 | 計算列表中的元素總和 | | [1, 2, 3] + [4, 5, 6] | [1, 2, 3, 4, 5, 6] | 以運算子 "+" 組合兩個列表 | | ['Hi!'] * 4 | ['Hi!', 'Hi!', 'Hi!', 'Hi!'] | 以運算子 "*" 重複輸出同一個列表 | | 3 in [1, 2, 3] | True | 以運算子 "in" 檢查 3 是否在列表裡面 | 列表中所進行的運算與字串運算十分相似,不過本小節用意主要還是幫大家複習一些運算子的應用。 ### 巢狀列表(nested-list) --- 簡單來說跟巢狀迴圈是一樣的概念,就是列表裡面在放一個列表,如下所示: ```python= [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]] # 註:以上是二維列表。 ``` 利用上述列表,我們可以結合巢狀迴圈這麼應用: ```python= a = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]] for i in range(len(a)): for j in range(0,5): print(a[i][j]) ``` 輸出結果: ```python= 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ``` 範例解析: 在變數 a 中,我們先將第一層做一個拆解: 首先 a[0] = [1,2,3,4,5],為一個列表,然後我們再進入第二層,也就是再加上一個中括號: a[0][0] = 1,就能夠得到第一層中那個列表,那個第一層列表中的第一個元素的值。 之後就以此類推:a[0][1] = 2 等等... 我們看到 for 迴圈的地方,一樣先拆解第一層的代碼塊: for i in range(len(a)) 的意思就是將 range(len(a)) 做迭代,而 len(a) 就是第一層的元素總和,也就是那個[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15],總共有三個,所以 range(len(a)) 就會將變數 i 從 0 遞增到 2,總共迭代三次。 首先第一次,我們會直接進入到 for 迴圈的第二層結構:for j in range(0,5) 這個代表說會迭代 0 ~ 4,並且存入變數 j 進行遞增。 第二層的第一次迭代(for j in range(0,5)): a[0][0] 第二層的第二次迭代(for j in range(0,5)): a[0][1] ... 第二層的第五次迭代(for j in range(0,5)): a[0][4] 目前的狀況是,我們處於第一層的 for 迴圈中的第一次迭代,然而第一層的 for 迴圈裡面,還具有一層 for 迴圈,我們暫且稱他為第二層的 for 迴圈,而又在第二層 for 迴圈裡面,我們會迭代五次(從 0 ~ 4)。 因為還在第一層 for 迴圈的第一次迭代這個狀態中,所以 i 值並不會改變,從頭到尾都是 0,因此我們便可以從 [1,2,3,4,5] 裡面不斷印出數字出來。 依照這個原理,在當第二層 for 迴圈結束後,便會進回到第一層 for 迴圈進行下一次的迭代,以此類推。 巢狀列表在我們 Python 基本資料結構裡面的實作是非常重要的一環,所以才會將範例做一個解析,希望各位能夠清晰明瞭。 :::success 快速整理! 巢狀列表:列表裡面的元素之資料型態還是列表。`[[1,2,3], [1,2,3], [1,2,3]]` 巢狀迴圈:迴圈之下還有一個迴圈。 ```python= for i in range(10): for j in range(5): pass ``` 以上是巢狀迴圈的範例,i = 1 時,j 會跑 5 次,i = 2 時,j 還是會跑 5 次,所以每次 i 變動時,j 就會從 0 ~ 4 遞增,執行 5 次。總體會執行 50 次。 ::: ### 列表函數及方法(functions / methods) --- | Number | 函數 | | -------- | -------- | | 1 | **len(list)**:計算列表元素總和 | | 2 | **max(list)**:回傳列表的最大值 | | 3 | **min(list)**:回傳列表的最小值 | | 4 | **list(seq)**:將序列轉換成列表資料型態 | | Number | 方法 | | -------- | -------- | | 1 | **list.append(obj)**:在列表尾端新增新的物件 | | 2 | **list.count(obj)**:計算某元素在列表中出現的次數 | | 3 | **list.extend(seq)**:在列表末尾一次性追加另一個序列中的多個值(用新列表擴展原來的列表) | | 4 | **list.index(obj)**:從列表中找出某個值第一個匹配項的索引位置 | | 5 | **list.insert(index, obj)**:將物件插入列表中,index 為欲插入該列表中的元素索引值,obj 為物件 | | 6 | **list.pop([index=-1])**:移除列表中的一個元素,索引預設為列表的末端(-1) | | 7 | **list.remove(obj)**:移除列表中某個值(obj)的第一個匹配項 -> 在括號內輸入指定值,python 會自動尋找指定刪除的值並刪除它,但輸入列表中不存在的值會 error | | 8 | **list.reverse()**:反轉列表的元素索引值 | | 9 | **list.sort(key=None, reverse=False)**:對列表進行排序,若 reverse=False,則排序由小到大,否則反之。 | | 9 | **list.clear()**:清空整個列表 | | 10 | **list.copy()**:複製列表 | 以下是一個練習範例: ```python= my_list = [] # append() 方法:在列表最末端中(意即從 index = -1)新增元素 my_list.append(10) my_list.append(5) my_list.append(8) print("原始列表:", my_list) # [10, 5, 8] # len() 函數計算列表中的元素總和 length = len(my_list) print("列表長度:", length) # 3 # max() 函數回傳列表中的最大值 max_value = max(my_list) print("列表中的最大值:", max_value) # 10 # min() 函數回傳列表中的最小值 min_value = min(my_list) print("列表中的最小值:", min_value) # 5 # sort() 方法:對列表進行升序排序 my_list.sort() print("排序後的列表:", my_list) # [5, 8, 10] # reverse() 方法:反轉列表 my_list.reverse() print("反轉後的列表:", my_list) # [10, 8, 5] # count() 方法:計算某個元素在列表中出現的次數 count_10 = my_list.count(10) print("列表中數字 10 出現的次數:", count_10) # 1 # pop() 方法:移除列表最末端(意即 index = -1)的元素 removed_element = my_list.pop() print("移除的元素:", removed_element) # 5 print("移除後的列表:", my_list) # [10, 8] # clear() 方法:清空列表 my_list.clear() print("清空後的列表:", my_list) # [] ``` 元組(Tuple) --- 在 Python 中,元組與列表的用法類似,但差異之處就在於元組的值是不能夠進行修改的。 不知道各位有沒有在 C 語言中學過常數(Constant)這個概念,如有學過,那麼你只要將這概念投射到元組上即可,把它想成是一個常數版本的陣列(C 語言中,列表的功用和陣列相似(arrays),可以把陣列想成是運算速度很快的列表)。 要使用元組這個資料型態,須以小括號 () 括起來,不同於列表的中括號 []。 元組的創建基本上與列表相同,加入相應元素即可: `tup1 = (1,2,3,4,5)` 創建一個空元組可這樣寫: `tup1 = ()` 在這裡我們需要注意的是:元組若只有一個元素,必須加上一個逗號,否則會被當成另一個資料型態使用。 註:以下範例環境在 IDLE Shell 中進行。 ```python= >>> tup1 = (1) >>> type(tup1) # 不加逗號,型態為整數(int) <class 'int'> >>> tup1 = (1,) >>> type(tup1) # 加上逗號,型態為元組(tuple) <class 'tuple'> ``` 另外值得一提的是,元組不加上小括號也是能夠成立的: ```python= >>> tup1 = "a", "b", "c", "d" >>> type(tup1) <class 'tuple'> >>> tup2 = 4, 3, 2, 1 >>> type(tup2) <class 'tuple'> ``` 同樣地,元組的索引一樣是從 0 開始,也可以進行截取、組合。 由於前面已經敘述過多次截取、組合的內容,於是本節便不再詳細介紹。 另外使用元組的優點具以下三點: 1. 讀取速度比列表快 2. 占用的空間較少 3. 資料更為安全(因為不能資料被修改) ### 強制修改元組內容 --- > 使用串列 list 存取 tuple 資料,修改資料後,再轉換為新的 tuple ( 注意,雖然變數名稱相同,但兩個 tuple 是完全不同的 )。 ```python= a = ('apple','banana','orange') b = list(a) b.append('grap') a = tuple(b) print(a) # ('apple', 'banana', 'orange', 'grap') ``` 說明兩個 tuple 是完全不同的,是因為兩者之間(被修改前與修改後的變數 a)的數值(value)並未完全相同,且使用 id() 函數得知,兩者的記憶體位址是不一樣的: ```python= >>> a = ('apple','banana','orange') >>> id(a) >>> 2080064319872 >>> b = list(a) >>> b.append('grap') >>> a = tuple(b) >>> id(a) >>> 2080059268272 #記憶體位址不一樣 ``` ### 運算(operation) --- 1. **len(tuple)**:計算元組總共所有的元素 2. **(1,2,3) + (4,5,6)**:兩元組可用 `+` 號連結。 3. **元組可以用 `*` 號來進行重複複製。** 那元組的運算基本上與列表都差不多,大概就是這樣而已。 至於元組的索引及擷取方式,其實也跟列表是一樣的,如下所示: ```python= >>> a = (1,2,3,4,5,6,7) >>> print(a[0]) 1 >>> print(a[:0]) () >>> print(a[:-1]) (1, 2, 3, 4, 5, 6) ``` 集合(Set) --- > 集合 ( set ) 就像是「只有鍵,沒有值」的字典,一個集合裡所有的鍵都不會重複,因為集合不會包含重複的資料的特性,常用來進行去除重複的字元、或判斷元素間是否有交集、聯集或差集之類的關聯性。 總之,集合是一個無序不重複的元素序列。 集合中的元素不會重複,並且可以進行交集、並集、差集等等的操作。 Python 中,要創建一個集合,與列表、元組不同的是,我們要使用大括號 {} 來表示一個集合,至於元素的部分我們就不再贅述,因為基本上都是一樣的,集合的定義如下所示: ```python= parame = {value01, value02,...} # or like this set(value) ``` 以下是一個範例(出自菜鳥教程): ```python= set1 = {1, 2, 3, 4} # 直接使用大括號創造集合 set2 = set([4, 5, 6, 7]) # 使用 set() 函數從列表創建集合 ``` > **注意:建立一個空集合必須用 set() 而不是 {},因為 {} 是用來建立一個空字典。** 不過作者在這邊建議:如果要建立一個集合的話就使用 set() 函數建立,否則很容易跟字典混淆。 :::success 快速整理! 集合(set):無序且「不重複(很重要)」的資料集合,如下: ```python= >>> set1 = set([1,2,3,4,5,6,2,2,3]) >>> print(set1) {1, 2, 3, 4, 5, 6} ``` 無序(Unordered):集合中的元素沒有特定的順序,表示每次存取元素時,其排列順序可能會有所不同。 ::: ### 運算(operation) --- **s.add(x)**:將元素 x 新增到集合 s 當中,範例如下所示: ```python= >>> a = set((1,2,3,4)) >>> a.add(5) >>> print(a) {1, 2, 3, 4, 5} ``` > 還有一個方法,也可以加入元素,且參數可以是列表,元組,字典等,語法格式如下: **s.update(x)**:同 s.add(x),不過 x 可以有多個。 ```python= >>> a = set((1,2,3,4)) >>> a.update({5,6,7,8}) >>> print(a) {1, 2, 3, 4, 5, 6, 7, 8} ``` ```python= >>> b = set((9,10,11,12,13)) >>> b.update([14,15,16,17,18]) >>> print(b) {9, 10, 11, 12, 13, 14, 15, 16, 17, 18} ``` **s.remove(x)**:將元素 x 從集合 s 移除,如果元素不存在,則會發生錯誤。 ```python= >>> a = set((1,2,3,4)) >>> a.remove(1) >>> print(a) {2, 3, 4} >>> a.remove(0) # 因為在集合 a 當中找不到 0 元素存在,所以報錯。 Traceback (most recent call last): File "<pyshell#16>", line 1, in <module> a.remove(0) KeyError: 0 ``` > 另外還有一個方法也是移除集合中的元素,且如果元素不存在,不會發生錯誤。格式如下圖所示: **s.discard(x)**:同 s.remove(x),不過當找不到元素 x 時不會發生錯誤。 ```python= >>> a = set((1,2,3,4)) >>> a.discard(0) # 不會發生錯誤 ``` > 我們也可以設定隨機刪除集合中的一個元素,語法格式如下: **s.pop()**:隨機刪除集合中的一個元素。 以上這些都是針對集合(Set)的新增、刪除的方法介紹,待後續將列出完整的方法表格。 ### 交集、聯集、差集、對稱差集 --- ![image](https://hackmd.io/_uploads/H1o994NkR.png) 圖源:[集合 set - Python 教學 | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/basic/set.html) 這個交集、聯集呢,跟我們在數學上學的是一樣的,只是這個概念被挪到程式語言上來用而已。 交集(數學上):A ∩ B(包含集合 A 與集合 B 共同擁有的元素) 聯集(數學上):A U B(包含集合 A 跟集合 B 的所有元素) 差集(數學上):A - B(包含集合 A,但不包含集合 B 的所有元素) 對稱差集(數學上):A△B(不包含集合 A 與集合 B 共同擁有的元素,也就是說 A ∩ B 以外的所有元素。) 說完數學上的意義,接下來讓我們回到程式語言的部分: | 集合 | 方法 | 運算子 | | -------- | -------- | -------- | | 交集 | a.intersection(b) | a&b | | 聯集 | a.union(b) | a|b | | 差集 | a.difference(b) | a-b | | 對稱差集 | a.symmetric_difference(b) | a^b | ```python= a = {1,2,3,4,5} b = {3,4,5,6,7} # 交集 print(a.intersection(b)) # {3, 4, 5} print(a&b) # {3, 4, 5} # 聯集 print(a.union(b)) # {1, 2, 3, 4, 5, 6, 7} print(a|b) # {1, 2, 3, 4, 5, 6, 7} # 差集 print(a.difference(b)) # {1, 2} print(a-b) # {1, 2} # 對稱差集 print(a.symmetric_difference(b)) # {1, 2, 6, 7} print(a^b) # {1, 2, 6, 7} ``` 以上範例、圖表源自於:[集合 set - Python 教學 | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/basic/set.html) ### 集合方法(methods) --- | 方法(Method) | 敘述(description) | | -------- | -------- | | add() | 為集合新增元素 | | clear() | 移除集合中的所有元素 | | copy() | 複製一個集合 | | difference() | 差集:回傳多個集合的差集 | | difference_update() | 差集:移除集合中的元素,該元素在指定的集合也存在 | | discard() | 刪除集合中指定的元素 | | intersection() | 交集:回傳集合的交集 | | intersection_update() | 交集:回傳集合的交集 | | isdisjoint() | 判斷兩個集合是否包含相同的元素,如果沒有回傳 True,否則回傳 False | | issubset() | 判斷指定集合是否為該方法參數集合的子集 | | issuperset() | 判斷方法的參數集合是否為指定集合的子集 | | pop() | 隨機移除元素 | | remove() | 移除指定元素 | | symmetric_difference() | 對稱差集:回傳兩個集合中不重複的元素集合 | | symmetric_difference_update() | 對稱差集:移除目前集合中在另外一個指定集合相同的元素,並將另一個指定集合中不同的元素插入到目前集合中 | | union() | 聯集:回傳兩個集合的聯集 | | update() | 為集合添加元素 | | len() | 計算集合元素個數 | 表格來源:[Python3 集合 | 菜鳥教程](https://www.runoob.com/python3/python3-set.html) 以下是一個練習範例: ```python= # 建立兩個集合 set1 = {1, 2, 3, 4, 5} set2 = {4, 5, 6, 7, 8} # add(): 為集合新增元素 set1.add(9) print("After add(9):", set1) # clear(): 移除集合中的所有元素 temp_set = set1.copy() temp_set.clear() print("After clear():", temp_set) # copy(): 複製一個集合 set_copy = set1.copy() print("Copy of set1:", set_copy) # difference(): 差集,回傳多個集合的差集 diff_set = set1.difference(set2) print("Difference between set1 and set2:", diff_set) # difference_update(): 移除集合中的元素,該元素在指定的集合也存在 set1.difference_update(set2) print("After difference_update(set2):", set1) # discard(): 刪除集合中指定的元素 set1.discard(9) print("After discard(9):", set1) # intersection(): 交集,回傳集合的交集 set_inter = set1.intersection(set2) print("Intersection of set1 and set2:", set_inter) # intersection_update(): 交集,回傳集合的交集 set1.intersection_update(set2) print("After intersection_update(set2):", set1) # isdisjoint(): 判斷兩個集合是否包含相同的元素 disjoint_result = set1.isdisjoint(set2) print("Are set1 and set2 disjoint?:", disjoint_result) # issubset(): 判斷指定集合是否為該方法參數集合的子集 subset_result = set1.issubset(set2) print("Is set1 a subset of set2?:", subset_result) # issuperset(): 判斷方法的參數集合是否為指定集合的子集 superset_result = set2.issuperset(set1) print("Is set2 a superset of set1?:", superset_result) # pop(): 隨機移除元素 popped_element = set1.pop() print("Element popped from set1:", popped_element) print("After pop():", set1) # remove(): 移除指定元素 set2.remove(8) print("After remove(8) from set2:", set2) # symmetric_difference(): 對稱差集,回傳兩個集合中不重複的元素集合 sym_diff = set1.symmetric_difference(set2) print("Symmetric difference between set1 and set2:", sym_diff) # symmetric_difference_update(): 對稱差集 set1.symmetric_difference_update(set2) print("After symmetric_difference_update(set2):", set1) # union(): 聯集,回傳兩個集合的聯集 union_set = set1.union(set2) print("Union of set1 and set2:", union_set) # update(): 為集合添加元素 set1.update({10, 11}) print("After update({10, 11}):", set1) # len(): 計算集合元素個數 set_length = len(set1) print("Length of set1:", set_length) ``` 總結 --- | 相異處 | 列表(List) | 元組(Tuple) | 集合(Set) | | -------- | -------- | -------- | -------- | | 有序 or 無序 | 有序 | 有序 | 無序 | | 可變 or 不可變 | 可變(mutable) | 不可變(immutable) | 集合本身是可變的,但其元素不可變。 | | 定義 | 兩個中括號 `[]`,裡面放元素(element),元素間以逗點相隔 | 兩個小括號 `()`,裡面放元素(element),元素間以逗點相隔 | 兩個大括號 `{}`,裡面放元素(element),元素間以逗點相隔,但是元素並沒有所謂鍵值對,又稱沒有鍵值對的字典。或是可用函數 set() 建立集合。 | | 元素資料型態 | 任意 | 任意 | 不可變物件(immutable) | | 元素重複性 | 可重複 | 可重複 | 不重複 | | 記憶體消耗 | 相對較高 | 相對較低 | 相對較低 | | 適用情況 | 需要有序、可變的資料結構,如佇列(Queue)、堆疊(Stack)等 | 需要固定資料的情況,如函數參數、回傳值等 | 需要快速查找、不重複元素的情況,如集合運算、去重複等 | 以下是一些參考資料~ 參考資料 === [Python3 列表 | 菜鳥教程](https://www.runoob.com/python3/python3-list.html) [Python3 元組 | 菜鳥教程](https://www.runoob.com/python3/python3-tuple.html) [Python3 List sort()方法 | 菜鳥教程](https://www.runoob.com/python3/python3-att-list-sort.html) [Python序列(Sequence) - 小宇2 - 博客園](https://www.cnblogs.com/livingintruth/p/3254654.html) [元組 ( 數組 ) tuple - Python 教學 | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/basic/tuple.html) [集合 set - Python 教學 | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/basic/set.html) [Python3 集合 | 菜鳥教程](https://www.runoob.com/python3/python3-set.html) [對稱差 - 維基百科,自由的百科全書](https://zh.wikipedia.org/zh-tw/%E5%AF%B9%E7%A7%B0%E5%B7%AE)