2021年12月29日 星期三

Python 學習筆記 : 串列元素的排序

排序是演算法課程的 ABC, 在 Python 的容器物件中, 不可變的字串與元組 (tuple) 內容無法排序 (因為排序會改變元素的順序); 無序的字典 (dict) 與集合 (set) 當然也無法排序, 只有串列 (list) 可以排序. 本篇是最近複習串列排序時的測試紀錄, 參考書籍 : 


要對串列物件之內容排序有如下兩種方式 : 
  • 使用串列的 sort() 與 reverse() 方法 : 會直接改變原串列內元素的排序
  • 使用內建函式 sorted() : 傳回排序後的新串列 (不影響原串列)

1. 使用串列的 sort() 與 reverse() 方法排序與倒序 : 

呼叫 sort() 方法預設會將串列的元素值由小到大排列 (升冪), 如果是字串元素則依據其 Unicode 編碼排序, 如果要將元素值由大到小排列 (降冪), 則可傳入參數 reverse=True, 語法如下 : 

list_obj.sort([key=None, reverse=False])     

另外, 與串列元素順序有關的還有 reverse() 方法, 但它並不是將元素值由大到小降冪排序, 而是前軍做後軍, 後軍做前軍, 前後順序顛倒而已 (倒序), 嚴格來說不是排序, 語法如下 : 

list_obj.reverse()     

注意, reverse() 沒有任何參數. 順帶一提, reverse() 的倒序操作也可以用切片 [::-1] 來達成, 但[::-1] 與呼叫 reverse() 不同的是它不會改變原串列, 而是傳回倒序後的新串列, 例如 :

>>> lot=[2, 34, 16, 7, 18, 27]    
>>> new_lot=lot[::-1]    
>>> new_lot      
[27, 18, 7, 16, 34, 2]   
>>> lot      
[2, 34, 16, 7, 18, 27]    
>>> lot.reverse()       
>>> lot   
[27, 18, 7, 16, 34, 2]

sort() 方法有兩個備選參數, 其中 key 是在排序時要對每個元素呼叫的關鍵函式, 而 reverse 則是用來設定是要升冪或降冪排序 (預設是升冪), 例如 : 

>>> lot=[2, 34, 16, 7, 18, 27]    
>>> lot.sort()                                 # 預設升冪排序
>>> lot 
[2, 7, 16, 18, 27, 34]
>>> lot=[2, 34, 16, 7, 18, 27]   
>>> lot.sort(reverse=True)          # 指定降冪排序 
>>> lot   
[34, 27, 18, 16, 7, 2]   
>>> lot=[2, 34, 16, 7, 18, 27]  
>>> lot.reverse()                            # 倒序排列
>>> lot   
[27, 18, 7, 16, 34, 2]

元素若是字串則按照每一個字元的 Unicode 編碼值大小逐一比對排序, 可用內建函式 ord() 查詢字元的 Unicode 編碼值, 例如 :

>>> string=['cC', 'aA', 'bB', 'Aa', 'Cc', 'Bb']    
>>> string.sort()      
>>> string     
['Aa', 'Bb', 'Cc', 'aA', 'bB', 'cC']
>>> ord('A')      
65
>>> ord('a')   
97
>>> ord('B')   
66
>>> ord('b')    
98

可見 sort() 會依序從第一個字元開始一一比對 Unicode 編碼, 由於大寫字母的 Unicode 編碼比小寫的要小, 因此會排在前面. 任何語言的字串也是依據其 Unicode 編碼排序, 例如 : 

>>> list_obj=['a', '我', '我們', '愛', 'abc', '你']   
>>> list_obj.sort()     
>>> list_obj    
['a', 'abc', '你', '愛', '我', '我們']   
>>> ord('我')      
25105
>>> ord('愛')        
24859
>>> ord('你')   
20320

因為 '你' 的 Unicode 比 '愛' 的 Unicode 小, 所以 你' 排在 '愛' 的前面. 

布林值串列也可以排序, 它是按照 Ture 與 False 相對應的整數值 1 與 0 去排序, 因此 False 會排在最前面, 例如 :

>>> list_obj=[True, True, False, True, False]    
>>> list_obj.sort()      
>>> list_obj       
[False, False, True, True, True]        # False 的值為 0, True 為 1, 故 False 排在前面

注意, 串列元素必須都是同類型資料才能呼叫 sort(), 否則會出現 TypeError 錯誤, 具體而言就是元素中有數值與字串混合情況的串列無法排序, 但布林值可以跟數值一起排序, 因為布林值其實就是 0 與 1 兩個整數. 而 reverse() 只是倒序操作而已, 並不涉及元素排序, 因此混合型態的串列呼叫 reverse() 是可以的, 例如 : 

>> list_obj=['abc', 123]     
>>> list_obj.sort()                              # 數值與字串混合的串列不可呼叫 sort()
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'  
>>> list_obj.reverse()                        # 混合型態串列可以呼叫 reverse()
>>> list_obj    
[123, 'abc']
>>> list_obj=['abc', True]                 # 字串與布林值為混合型態, 不可排序
>>> list_obj.sort()     
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'bool' and 'str'
>>> list_obj.reverse()                        # 混合型態串列可以呼叫 reverse()
>>> list_obj    
[True, 'abc']
>>> list_obj=[3.14159, 123, True]    # 布林值本質是整數, 與數值並非混合型態        
>>> list_obj.sort()                              
>>> list_obj    
[True, 3.14159, 123]

除了混合資料型態的串列無法呼叫 sort() 進行排序外, 複數串列也不行, 例如 : 

>>> list_obj=[1+2j, 1+1j, 1-1j]    
>>> list_obj.sort()    
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'complex' and 'complex'    


2. 使用內建函式 sorted() 排序 : 

內建函式 sorted() 會將傳入串列預設以升冪排序後傳會心串列 (傳入 reverse=True 則可降冪排序), 不會改變原串列, 語法如下 : 

sorted(list_obj [, key=None, reverse=False])     

備選參數的用法與 sort() 方法的一樣, 例如 : 

>>> lot=[2, 34, 16, 7, 18, 27]    
>>> sorted(lot)                               # 傳回升冪排序後的新串列
[2, 7, 16, 18, 27, 34]
>>> sorted(lot, reverse=True)      #  傳回降冪排序後的新串列
[34, 27, 18, 16, 7, 2]
>>> lot                                            # 原串列不變
[2, 34, 16, 7, 18, 27]

字串串列同樣是以 Unicode 編碼排序, 例如 :

>>> string=['cC', 'aA', 'bB', 'Aa', 'Cc', 'Bb']    
>>> sorted(string)                                                # 傳回升冪排序後的新串列
['Aa', 'Bb', 'Cc', 'aA', 'bB', 'cC']
>>> sorted(string, reverse=True)                       #  傳回降冪排序後的新串列
['cC', 'bB', 'aA', 'Cc', 'Bb', 'Aa']
>>> string                                                             # 原串列不變
['cC', 'aA', 'bB', 'Aa', 'Cc', 'Bb']  

與 sort() 方法一樣, 數值與字串混合的串列, 以及複數串列都無法用 sorted() 排序, 例如 :

>>> list_obj=['abc', 123]                # 數值與字串混合 : 無法排序
>>> sorted(list_obj)   
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'
>>> list_obj=['abc', True] 
>>> sorted(list_obj)
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'bool' and 'str'
>>> list_obj=[1+2j, 1+1j, 1-1j]      # 複數串列無法排序
>>> sorted(list_obj)   
Traceback (most recent call last):
  File "<pyshell>", line 1, in <module>
TypeError: '<' not supported between instances of 'complex' and 'complex'

參考 :



沒有留言 :