[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
- 期末总结