map/reduce
Python内建了map()
和reduce()
函数。
我们先来看map,map()
函数内置了两个参数,一个是函数,一个是Iterable
,map
将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator
返回。
所以map()
函数的语法是:
map(function, iterable, …)
#function–函数
#iterable–一个或多个序列
举个例子,我们可以用map()
函数计算一个序列的平方,现在我们有个函数f(x)=x2
def f(x):
... return x*x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
为什么要用list()
函数呢,因为结果r
返回的是Iterator
,它是一个惰性序列,之前我们讲过,需要一次次的调用next()
,所以通过list()
函数让它把整个序列都计算出来并返回一个list。
当然,你可能会想到用循环也能计算出这样的结果
L = []
for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
L.append(f(n))
print(L)
是的,确实可以,BUT你可以通过上面的代码一眼就看出我们是要“把f(x)作用在list的每一个元素并把结果生成一个新的list”吗?
显然不能
map()
作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2
,还可以计算任意复杂的函数
例如将两个列表,对相同位置的列表数据进行相加:
>>> list(map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]))
[3, 7, 11, 15, 19]
只需要一行代码
接下来我们来看reduce
reduce() 函数会对参数序列中元素进行累积。
函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
就相当于做累计计算,例如:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
我们可以用reduce
写一个序列求和:
>>> from functools import reduce
>>> def add(x, y) : # 两数相加
... return x + y
...
>>> reduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
15
当然求和运算可以直接用Python内建函数sum()
,没必要动用reduce
但如果我们要把序列[1,2,3,4,5]
,变换成整数12345
,这时候reduce
就排上用场了:
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
...
>>> reduce(fn, [1, 2, 3, 4, 5])
12345
这个例子的作用并不大,让我们来看点硬的,首先考虑到字符串str
也是一个序列,对上面的例子稍加改动,配合map()
,我们就可以写出把str
转换为int
的函数:
>>> from functools import reduce
>>> def fn(x, y):
... return x * 10 + y
...
>>> def change(s)
... group = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5}
... return group[s]
...
>>> reduce(fn, map(change '12345'))
12345
整理一下:
>>> from functools import reduce
GROUP = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5}
def all(s):
def fn(x, y):
return x * 10 + y
def change(s)
return GROUP[s]
reduce(fn, map(change '12345'))
12345
也就是说,假设Python没有提供int()
函数,你完全可以自己写一个把字符串转化为整数的函数,而且只需要几行代码!