2.3 Python常用高阶函数

在Python中,高阶函数的抽象能力是非常强大的,如果用户在代码中善于利用这些高阶函数,则可以使代码变得简洁明了。

2.3.1 map()函数:数组迭代

Python内建了map()函数,该函数可以接收两个参数:一个是函数,另一个是迭代器(Iterator),map()函数将传入的函数依次作用到序列的每一个元素上,并把结果作为新的迭代器(Iterator)返回。

例如,求一个数值型列表中各个数值的立方,返回的还是列表,就可以使用map()函数实现,代码如下:

img

代码输出结果如下所示。

img

map()函数传入的第1个参数是f,即函数对象本身。由于结果r是一个迭代器,迭代器是惰性序列,因此通过list()函数计算整个序列,并返回一个列表。

其实,这里可以不需要使用map()函数,编写一个循环也可以实现该功能,代码如下:

img

代码输出结果如下所示。

img

所以,map()函数作为高阶函数,它把运算规则抽象化。因此,我们不但可以计算简单的f(x)=x**3,还可以计算任意复杂的函数。例如,把列表中所有的数字转为字符串,代码如下:

img

代码输出结果如下所示。

img

从输出可以看出,列表中所有的数字都被转为了字符串。

2.3.2 reduce()函数:序列累积

reduce()函数可以接收3个参数:一个函数f()、一个列表list、一个可选的初始值,初始值的默认值是0,reduce()函数传入的函数f()必须接收两个参数,对列表(list)的每个元素反复调用f()函数,并返回最终计算结果。

例如,计算列表[1,2,3,4,5]中所有数值的和,初始值是100,代码如下:

img

代码输出结果如下所示。

img

此外,还可以使用lambda()函数进一步简化程序,代码如下:

img

代码输出结果如下所示。

115

2.3.3 filter()函数:数值过滤

Python内建的filter()函数用于过滤序列,与map()函数的作用类似,filter()函数也需要接收一个函数和一个序列。与map()函数作用不同的是,filter()函数把传入的函数依次作用于每一个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

例如,利用filter()函数过滤出1~100中平方根是整数的数,代码如下:

img

代码输出结果如下所示。

img

其中,math.sqrt()是求平方根函数。

此外,filter()函数还可以处理缺失值。例如,将一个序列中的空字符串全部删除,代码如下:

img

代码输出结果如下所示。

img

从输出结果可以看出,使用filter()函数,关键在于正确选择一个筛选函数。

注意:filter()函数返回的是一个迭代器(Iterator),也就是一个惰性序列,计算结果都需要使用list()函数获得所有结果并返回列表。

2.3.4 sorted()函数:列表排序

排序也是在程序中经常用到的算法。无论是使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,则可以直接比较。如果是字符串或两个字典,则直接比较数学上的大小是没有意义的。因此,比较的过程必须通过函数抽象出来。

Python内置的sorted()函数就可以对列表进行排序,代码如下:

img

代码输出结果如下所示。

img

此外,sorted()函数也是一个高阶函数,可以接收一个key()函数来实现自定义的排序。例如,按绝对值大小进行排序,代码如下:

img

代码输出结果如下所示。

img

key指定的函数将作用于列表中的每一个元素,并根据key()函数返回的结果进行排序。

我们再看一个字符串排序的示例,代码如下:

img

代码输出结果如下所示。

img

在默认情况下,对字符串排序是按照ASCII码值的大小进行排序的,大写字母会排列在小写字母的前面。

现在,我们提出排序时忽略字母大小写,按照字母顺序排序。要实现这个算法,不必对现有代码大加改动,只需要使用一个key()函数把字符串映射为忽略字母大小写的排序即可。忽略字母大小写来比较两个字符串,实际上就是先把字符串都变成大写字母(或都变成小写字母),再比较。

这样,我们在sorted()函数中传入key()函数,即可实现忽略字母大小写的排序,代码如下:

img

代码输出结果如下所示。

img

要进行反向排序,不必修改key()函数,可以传入第3个参数reverse=True,代码如下:

img

代码输出结果如下所示。

img