filter和sorted是经典的Python高阶函数。他们都是通过将函数名作为参数实现高阶的函数调用,达到筛选和排序的目的。

filter函数

filter函数是Python的内建函数,用于过滤序列。

它接收一个函数和一个序列。

把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

这里的重点在于,作为参数的函数,必须返回的是一个布尔型的值(或者是0或非0的数值)。

举例说明:

假设有如下需求:在一个list中,删掉偶数,只保留奇数

此时,可以先建立一个函数is_odd,判断是不是一个奇数。

def  is_odd(n):
    return n % 2 == 1

接下来就可以构建一个filter函数如下:

filter(is_odd,[1,2,4,5,6,9,10,15])

filter返回的是一个filter对象,是一个Iterator。需要使用list构造函数来强制转换为实际数据。

list(filter(is_odd,[1,2,4,5,6,9,10,15]))
#结果:[1,5,9,15]

这里要注意。is_odd函数,如果只是写return n % 2行不行呢?

答案是肯定的。因为返回0表示假值,其余为真。

再举一个例子

把一个序列中的空字符串删掉

首先,先构建一个函数not_empty,判断是不是空字符串

def not_empty(s):
    return s and s.strip()

接下来构建一个filter函数如下:

list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))
# 结果: ['A', 'B', 'C']

再来一个例子:

用filter求素数

埃式筛法

首先,列出2开始的所有自然数,构造序列

取序列第一个数2,他一定是素数,筛掉2的倍数。

取新序列的第一个数3,它一定是素数,筛掉3的倍数。

取新序列的第一个数5,它一定是素数,筛掉5的倍数。

不断筛选,得到所有素数。

具体实现方法:

先用生成器构造从3开始的奇数序列:

def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n

再定义筛选函数

_not_divisible(n):
   return lambda x: x % n > 0

相当于

def _not_divisible(n):
    def fun(x):
        return x % n > 0
    return fun

正常来说,一个筛选函数只能有一个参数,用来放置实际筛选的对象。

例如:is_odd(n),可以用来筛选一个序列中所有基数,写成filter(is_odd,L)。

这其中is_odd是以一个函数名形式作为实参放进来。

但是对于本例来说,筛选函数_not_divisible要在一个序列(假设是L = [1,2,3,4,5])中筛选出不能被n整除的元素。如果n是一个常数,比如5。

那大可以写成:

def _not_divisible(x):
    return x % 5 > 0

这样一来,可以使用函数filter(_not_divisible, L)来将L中所有的不能被5整除的数过滤出来。

然而,本例中n是个变量,加上原本的x,就是两个变量。不能写成:

def _not_divisible(x, n):
    return x % n > 0

这样写会让filter函数语法错误。导致n无法传递给filter函数。

因此,采用了返回函数的方式。利用内嵌函数fun(x),或者例子中提到的lambda,作为函数_not_divisible(n)的返回值,相当于将n的值传递进fun函数(lambda函数),而又使得fun函数(lambda函数)有一个参数x,符合fitler函数的第一个函数参数标准,用于筛选。这恰恰是函数式编程的精髓。

最后,定义一个生成器,不断返回下一个素数。

def primes():
    yield 2
    it = _odd_iter() # 初始序列
    while True:
        n = next(it) # 返回序列的第一个数
        yield n
        it = filter(_not_divisible(n), it) # 构造新序列

由于primes()也是一个无限序列,所以调用时需要设置一个退出循环的条件

# 打印1000以内的素数:
for n in primes():
    if n < 1000:
        print(n)
    else:
        break

关于返回函数的函数

举个例子:写一个筛选函数times(n),从一个列表L中删选出是n的倍数的元素。

注意,filter函数返回的也是一个算法,也就是一个Iterator。 list()可以将其转化为一个普通列表。 next和函数调用同样可以滞后输出。

应该构建一个筛选函数,可以返回一个带一个参数x的函数 利用参数n,完成对n的倍数的筛选。 并在filter函数中利用。

def times(n):
    return lambda x: x % n == 0

#1.list用法
print(list(filter(times(5), [1, 2, 5, 10, 12])))

#2.next用法
mm = filter(times(5), [1, 2, 5, 12, 10])
print(next(mm))
print(next(mm))

#3.函数调用用法
mm = filter(times(5), [1, 2, 5, 12, 10])
for n in mm:
    print(n)

再举个例子:

筛选回数

回数是指从左向右读和从右向左读都是一样的数,例如12321,909。请利用filter()筛选出回数:

算法提示:先变成字符串,再考查字符串与反字符串是否相等。回文条件。

代码如下:

# # -*- coding: utf-8 -*-
def is_palindrome(n):
    s = str(n)
    return s == s[::-1]
# 测试:
output = filter(is_palindrome, range(1, 1000))
print('1~1000:', list(output))
if list(filter(is_palindrome, range(1, 200))) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]:
    print('测试成功!')
else:
    print('测试失败!')

好啦。就讲到这里。

看懂了就点个赞吧。