[TOC]
### 引入
Python內建的`filter()`函數用于過濾序列。
和`map()`類似,`filter()`也接收一個函數和一個序列。和`map()`不同的是,`filter()`把傳入的函數依次作用于每個元素,然后根據返回值是`True`還是`False`決定保留還是丟棄該元素。
### 篩選”函數
例如,在一個`list`中,刪掉偶數,只保留奇數,可以這么寫:
~~~
def is_odd(n):
return n % 2 == 1
list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
~~~
結果: [1, 5, 9, 15]
把一個序列中的空字符串刪掉,可以這么寫:
~~~
def not_empty(s):
return s and s.strip()
list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
~~~
結果: ['A', 'B', 'C']
可見用`filter()`這個高階函數,關鍵在于正確實現一個“篩選”函數。
注意到`filter()`函數返回的是一個`Iterator`,也就是一個惰性序列,所以要強迫`filter()`完成計算結果,需要用`list()`函數獲得所有結果并返回`list`。
### 求素數
用`filter`求素數
計算素數的一個方法是埃氏篩法,它的算法理解起來非常簡單:
首先,列出從2開始的所有自然數,構造一個序列:
`2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...`
取序列的第一個數2,它一定是素數,然后用2把序列的2的倍數篩掉:
`3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...`
取新序列的第一個數3,它一定是素數,然后用3把序列的3的倍數篩掉:
`5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...`
取新序列的第一個數5,然后用5把序列的5的倍數篩掉:
`7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...`
不斷篩下去,就可以得到所有的素數。
用Python來實現這個算法,可以先構造一個從3開始的奇數序列:
~~~
def _odd_iter():
n = 1
while True:
n = n + 2
yield n
~~~
注意這是一個生成器,并且是一個無限序列。
然后定義一個篩選函數:
~~~
def _not_divisible(n):
return lambda x: x % n > 0
~~~
最后,定義一個生成器,不斷返回下一個素數:
~~~
def primes():
yield 2
it = _odd_iter() # 初始序列
while True:
n = next(it) # 返回序列的第一個數
yield n
it = filter(_not_divisible(n), it) # 構造新序列
~~~
這個生成器先返回第一個素數2,然后,利用`filter()`不斷產生篩選后的新的序列。
由于`primes()`也是一個無限序列,所以調用時需要設置一個退出循環的條件:
打印1000以內的素數:
~~~
for n in primes():
if n < 1000:
print(n)
else:
break
~~~
注意到`Iterator`是惰性計算的序列,所以我們可以用Python表示“全體自然數”,“全體素數”這樣的序列,而代碼非常簡潔。
### 練習
回數是指從左向右讀和從右向左讀都是一樣的數,例如12321,909。請利用`filter()`濾掉非回數:
~~~
# -*- coding: utf-8 -*-
def is_palindrome(n):
pass
# 測試:
output = filter(is_palindrome, range(1, 1000))
print(list(output))
~~~
#### 參考源碼
~~~
# -*- coding: utf-8 -*-
def is_palindrome(n):
s = str(n)
l = len(s)
print(l)
hl = int(l/2) + int(l % 2)
print(hl)
le = 0
while le < hl:
if s[le] != s[l-le-1]:
return
le += 1
return n
output = filter(is_palindrome, range(1, 1000))
print(list(output))
~~~
### 小結
filter()的作用是從一個序列中篩出符合條件的元素。由于filter()使用了惰性計算,所以只有在取filter()結果的時候,才會真正篩選并每次返回下一個篩出的元素。
- Python教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個 Python 程序
- 使用文本編輯器
- Python代碼運行助手
- 輸入和輸出
- 源碼
- learning.py
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷
- 循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 迭代器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- Python函數式編程——偏函數(來自博客)
- 模塊
- 使用模塊
- 安裝第三方模塊
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 實例屬性和類屬性
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用枚舉類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- StringIO和BytesIO
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- datetime
- collections
- base64
- struct
- hashlib
- itertools
- contextlib
- XML
- HTMLParser
- urllib
- 常用第三方模塊
- PIL
- virtualenv
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 異步IO
- 協程
- asyncio
- async/await
- aiohttp
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫Web App骨架
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 編寫配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- FAQ
- 期末總結