2021年11月8日 星期一

Python 學習筆記 : 內建函式 filter() 的用法

Python 的內建函式 filter() 功能與 map() 類似, 都是把函式套用 (apply) 到可迭代物件的每一個元素上, 但不同的地方是傳入 filter() 的套用函式只能傳回 True/False, 而 filter() 只會將迭代時傳回 True 的元素留下, 然後放入迭代器物件中傳回; 而 map() 則是傳回所有結果, 亦即 filter() 則有過濾作用, 關於迭代參考 :

本篇測試參考了下列書籍 :

filter() 函式的語法如下 : 

filter(func, iterable)  

filter() 只有兩個必要參數, 第一個參數是用來過濾序列元素的函式, 它只能傳回 True 或 False (即傳回一個條件式的結果), 只有此函式回傳 True 的元素才會被 map() 傳回. 第二參數為一個可迭代物件, 例如字串, 元組, 串列, 字典, 或集合, 其元素會被逐一被過濾函式 func 迭代, 符合條件的元素才會被傳回.

filter() 的傳回值為一個 filter 物件, 它是可迭代物件, 也是迭代器物件, 可用 for 迴圈或 next() 走訪其元素, 也可以用 list() 或 tuple() 將其轉為串列或元組. filter() 的第一參數也可以傳入 None 而非函式, 這時 filter() 會傳回可迭代物件中值為 True 的元素 (即不是 0, False, None, 空字串, 空串列, 空元組, 空字典等). 

例如 :  

>>> even=filter(lambda i: i%2 == 0, range(10))      # 過濾序列中的偶數
>>> type(even)                                                             # 傳回值是 filter 物件
<class 'filter'>     
>>> even    
<filter object at 0x00000255D877D668>   
>>> hasattr(even, '__iter__')                                       # filter 是可迭代物件
True    
>>> hasattr(even, '__next__')                                      # filter 是迭代器物件
True    
>>> for i in even:                                                           # 用 for 迴圈走訪
    print(i)    
    
0
2
4
6
8
>>> list(even)                                                               # 走訪過元素已耗盡
[]
>>> even=filter(lambda i: i%2 == 0, range(10))      # 重新建立 filter 物件
>>> list(even)                                                               # 轉成串列
[0, 2, 4, 6, 8]
>>> tuple(even)                                                            # 無法重複轉換
()      
>>> even=filter(lambda i: i%2 == 0, range(10))       # 重新建立 filter 物件 
>>> tuple(even)                                                            # 轉成元組  
(0, 2, 4, 6, 8)

此例以一個 lambda 匿名函式過濾 range(10) 產生的連續整數序列, 走訪到偶數元素時 i%2==0 傳回 True, 奇數傳回 False, 故只有偶數會被 filter() 傳回來. 此過濾函式用 lambda 較簡潔, 當然也可以寫成具名函式, 例如 : 

>>> def is_even(i):         # 具名之過濾函式
    return i%2 ==0          # 偶數傳回 True, 否則傳回 False

>>> even=filter(is_even, range(10))        # 過濾偶數
>>> list(even)     
[0, 2, 4, 6, 8]    

如果要過濾奇數, 那只要將過濾函式改為 i%2==1 即可, 例如 :

>>> odd=filter(lambda i: i%2 == 1, range(10))    
>>> list(odd)    
[1, 3, 5, 7, 9]

下面的範例是過濾負數 :

>>> negatives=filter(lambda i: i < 0, [-2, 17, 0, 9, -6, -28])     # 過濾負數
>>> list(negatives)        # 轉成串列
[-2, -6, -28]   

可見只有負數被保留下來. 

filter() 的第一參數也可以傳入 None 而非過濾函式, 例如 : 

>>> list1=[False, 1, 0, None, 'Hello', '', 3.14, [], (), 1+2j, {}, True, set()]     
>>> list1   
[False, 1, 0, None, 'Hello', '', 3.14, [], (), (1+2j), {}, True, set()]        
>>> filtered=filter(None, list1)                                # None 會過濾所有非真內容  
>>> list(filtered)    
[1, 'Hello', 3.14, (1+2j), True]   

此例傳入 filter() 的第一參數是 None 不是函式, 可見 False, 0, 空字串, None, 空序列, 空集合等都會被濾掉. 傳入 None 相當於是傳入 bool() 函式, 例如 : 

>>> list1=[False, 1, 0None, 'Hello', '', 3.14, [], (), 1+2j, {}, True, set()] 
>>> filtered=filter(bool, list1)         # 傳回 bool() 求值為真者
>>> list(filtered)                               # 轉成串列
[1, 'Hello', 3.14, (1+2j), True]

可見結果與傳入 None 是一樣的.

filter() 的過濾功能為留下過濾函式傳回 True 的元素, 如果要過濾傳回 False 的元素可以使用內建模組 itertools 裡的 filterfalse() 函式, 其語法與 filter() 完全一樣, 差別只是它留下過濾函式傳回 False 的元素 :

from itertools import filterfalse     
filterfalse(func, iterable) 

例如 : 

>>> from itertools import filterfalse                                    # 匯入模組
>>> filtered=filterfalse(lambda i: i%2 == 0, range(10))     # 過濾傳回 False 者
>>> filtered   
<itertools.filterfalse object at 0x0000019FC19C8DD8>         # 傳回 filterfalse 物件
>>> type(filtered)     
<class 'itertools.filterfalse'>                                                      # 傳回 filterfalse 物件
>>> hasattr(filtered, '__iter__')                                             # 是可迭代物件
True   
>>> hasattr(filtered, '__next__')                                            # 是迭代器物件
True   
>>> list(filtered)                                                                       # 轉成串列
[1, 3, 5, 7, 9]

可見過濾函式傳回 False 的是奇數序列. 

itertools.filterfasle() 的第一參數也可以傳入 None 而非函式, 這樣值為 False 的物件像 False, 0, 空字串, None, 空序列, 空集合等會保留下來, 例如 : 

>>> list1=[False, 1, 0None, 'Hello', '', 3.14, [], (), 1+2j, {}, True, set()]   
>>> filtered=filterfalse(None, list1)          # 過濾 False 
>>> list(filtered)   
[False, 0, None, '', [], (), {}, set()]    

沒有留言 :