Python 的內建函式 filter() 功能與 map() 類似, 都是把函式套用 (apply) 到可迭代物件的每一個元素上, 但不同的地方是傳入 filter() 的套用函式只能傳回 True/False, 而 filter() 只會將迭代時傳回 True 的元素留下, 然後放入迭代器物件中傳回; 而 map() 則是傳回所有結果, 亦即 filter() 則有過濾作用, 關於迭代參考 :
本篇測試參考了下列書籍 :
- 精通 Python (碁峰, 2020) 第 7 章
- Python 3 程式庫參考手冊 (碁峰, 2012) 第二章
- Python 函式庫語法範例字典 (旗標, 2019) 第 4-35 節
- Python 入門邁向高手之路王者歸來 (深石, 2017) 8-11 節
- The Python 3 Standard Library by Example (Edison Weslly, 2017)
- Python最強入門邁向數據科學之路:王者歸來(全彩印刷第二版) 8-10 節
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, 0, None, '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, 0, None, 'Hello', '', 3.14, [], (), 1+2j, {}, True, set()]
>>> filtered=filterfalse(None, list1) # 過濾 False
>>> list(filtered)
[False, 0, None, '', [], (), {}, set()]
沒有留言:
張貼留言