Python 合并map()和reduce(),不难发现基于一些简单的定义就可以创建高阶函数。下面介绍如何组合map()
函数和reduce()
函数生成map-reduce
函数。
这个由map()
函数和reduce()
函数组成的函数有3个参数:一个映射操作,一个归约操作,以及一个待处理的数据序列。
上面的定义非常宽泛,很难从中看出对数据类型的要求。由于映射和归约可能是非常复杂的操作,下面更严格地定义map-reduce
函数:
该定义多了几项约束。首先,可迭代对象需要包含类型一致的数据,我们把这个类型绑定为T_
类型变量;然后,map()
函数接收类型为T_
的参数,并生成相同类型的结果;最后,归约函数接收两个T_
类型的参数,返回一个同类型的参数。对于一个简单的数值计算应用来说,使用类型变量T_
施加类型约束效果很好。
更多时候需要更严格地定义映射函数,例如Callable[[T1_], T2_]
就体现了映射函数的核心特点:输入类型T1_
和输出类型T2_
可能是不同的。归约函数则需要保证输入和输出函数类型一致:Callable[[T2_, T2_], T2_]
。
可以分别提供映射函数和归约函数来得到计算平方和的归约定义,如下所示:
这里使用了lambda y: y ** 2
作为平方计算的映射函数,归约部分使用lambda x, y: x + y
作为参数。无须专门指定初始值,因为它就是平方函数映射后序列的第一个值。
上面的参数lambda x, y: x + y
相当于+
运算符,Python的operator
模块中将所有算术运算符定义为短函数,下面用它简化上面的map-reduce
定义:
这里使用了operator.add
方法代替匿名函数来对数据进行求和。
计算可迭代对象中数值的个数如下所示:
首先通过lambda y: 1
将每个元素映射为1,再通过匿名函数或者operator.add
做归约汇总,就得到了元素的个数。
总的说来,可以使用reduce()
函数创建任何类型的归约,将大型数据集转换为单个数值。不过在使用reduce()
函数时,需要注意一些限制。
避免像下面这样使用reduce()
函数:
该函数能运行,Python可以把add
运算符应用于字符串集合,但使用"".join (list_of_strings)
效率更高。通过timit
测试发现使用reduce()
组合字符串的时间复杂度是 O(),且非常慢。在实际应用中,如果不仔细研究运算符处理复杂数据集的机制,很难发现效率的瓶颈在哪里。