Python filter()函数接收或舍弃数据,filter()
函数的作用是把一个判定函数(也称“谓词函数”)应用于集合中的每个值。如果谓词为真,接收该值,否则将其舍弃。itertools
模块中的filterfalse()
函数是filter()
函数的一个变体,第8章会介绍itertools
模块中filterfalse()
函数的用法。
下面利用filter()
函数过滤旅行数据,生成一个路径段长度大于50海里的子集:
long = list(
filter(lambda leg: dist(leg) >= 50, trip))
)
对于长路径段,谓词函数返回True
,这段路径通过测试,短路径则不能通过测试。最终有14个路径段通过了长度测试。
这种处理方法很好地区分了过滤规则(lambda leg: dist(leg) >= 50)
和其他处理过程,例如创建trip
对象和分析长距离路径段等。
另一个例子如下所示:
>>> filter(lambda x: x % 3 == 0 or x % 5 == 0, range(10))
<filter object at 0x101d5de50>
>>> sum(_)
23
这里创建了一个简单的匿名函数,测试输入值是否为3或者5的倍数,然后把它应用于一个可迭代对象range(10)
,返回一个由通过测试的数值组成的可迭代序列。
谓词函数为真的数包括[0, 3, 5, 6, 9]
,所以这些数据通过了测试,而谓词为假的数据都被舍弃了。
这个处理过程也可以用生成器表达式来完成,如下所示:
>>> list(x for x in range(10) if x % 3 == 0 or x % 5 == 0)
[0, 3, 5, 6, 9]
此处理过程的严格数学表述如下所示:
公式表明由 x 组成的集合满足在范围range(10)
中,并且x % 3 == 0
或者x % 5 == 0
,可以看到filter()
函数和公式形式的数学表述之间存在很好的对应关系。
filter()
函数中的谓词函数经常需要使用已定义的函数,而不是匿名函数。复用之前定义过的函数作为谓词函数的示例如下:
>>> from ch01_ex1 import isprimeg
>>> list(filter(isprimeg, range(100)))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
71, 73, 79, 83, 89, 97]
这里从另一个模块中导入了一个名为isprimeg()
的函数,然后将其应用于一个数值集合,保留质数,舍弃非质数。
用这种方法生成质数表的效率很低,它表面上的简洁类似于律师们常说的“保护儿童免受危险物品侵害原则”,看上去很好,实际上扩展性很差。isprimeg()
函数在计算每个值时都要重设测试条件,必须通过某种方法保存之前质数测试的计算结果。更好的方法是使用埃拉托斯特尼筛法(Sieve of Eratosthenes),该算法保留了之前得出的质数,因而可以避免大量低效的重复计算。