函数式编程之lambda、filter、map、reduce

匿名函数与lambda

python允许用lambda关键字来创建匿名函数。

lambda的语法: lambda [arg1[,arg2,…argN]]: expression

未使用lambda的函数代码如下:

1
2
def (x,y):
return x+y

使用lambda函数的代码如下:
lambda x,y: x+y

lambda函数的参数也可以使用默认参数,如下:

1
a = lambda x,y=2 : x+y

a(3) =>5,当只给一个参数时,y=2
a(3,5) =>8,当给出两个参数时,y=5

filter()

filter()的语法:filter(func,seq)
意思:调用一个布尔函数func来迭代遍历每个seq中的元素,返回一个使用func返回值为true的元素的序列

如果用纯python来写filter(),它或许就像这样:

1
2
3
4
5
6
def filter(bool_func,seq):
filtered_seq = []
for eachItem in seq:
if bool_func(eachItem):
filtered_seq.append(eachItem)
return filtered_seq

filter()示例

1
2
3
4
5
6
7
8
9
from random import randint
def odd(n):
return n%2
allNums = []
for eachNum in range(9):
allNums.append(randint(1,99))
print filter(odd,allNums)

第一次重构

1
2
3
4
5
6
from random import randint
allNums = []
for eachNum in range(9):
allNums.append(randint(1,99))
print filter(lambda n:n%2,allNums)

注: 在Python3中,如果直接打印 filter 将返回,可以用list()将 filter 转成列表后打印
示例:

1
print(list(filter(lambda n:n%2,allNums)))

第二次重构

1
2
3
4
5
6
from random import randint
allNums = []
for eachNum in range(9):
allNums.append(randint(1,99))
print [n for n in allNums if n%2]

第三次重构

1
2
3
from random import randint
print [n for n in [randint(1,99) for i in range(9)] if n%2]

map()

map()的语法:map(func,seq1[,seq2…])
意思:将函数func作用于给定(s)的每个元素,并用一个列表来提供返回值;如果func为None,func表现为一个身份函数,返回一个含有每个序列中元素集合的n个元组的列表。

如果用纯python来写map(),它或许就像这样:

1
2
3
4
5
def map(func,seq):
mapped_seq = []
for eachItem in seq:
mapped_seq.append(func(eachItem))
return mapped_seq

1
map((lambda x: x+2),[0,1,2,3,4,5])

==>[2,3,4,5,6,7]
注: 在Python3中,如果直接打印 map 将返回,可以用list()将 map 转成列表后打印
示例:

1
print(list(map(lambda x: x+2, [0,1,2,3,4,5])))

map也可以被序列来替代

1
[x+2 for x in range(6)]

map也可以和多个序列一起运作

1
map(lambda x,y: x+y,[1,3,5],[2,4,6])

==>[3,7,11]

当map的func为None时,就相当于将各序列每次各取一个值,组成一个元组

1
map(None,[1,3,5],[2,4,6])

==> [(1,2),(3,4),(5,6)]

1
zip([1,3,5],[2,4,6])

==> [(1,2),(3,4),(5,6)]

reduce()

reduce()的语法:reduce(func,seq[,init])
意思:将二元函数作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列元素),连续的将现有的结果和下一个值作用在获得的随后的结果上,最后减少我们的序列为一个单一的返回值;如果初始值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素。

如果用纯python来写reduce(),它或许就像这样:

1
2
3
4
5
6
7
if init is None:
res = lseq.pop(0)
else:
res = init
for item in lseq:
res = bin_func(res,item)
return res


1
print 'the total is: ' , reduce((lambda x,y:x+y),range(5))

==> the total is: 10
注: 在Python3中,reduce已经移到了functools
示例:

1
2
import functors
print('the total is: ' , functools.reduce((lambda x,y:x+y),range(5)))

小结:

lambda: 就相当于是一个没有名字的函数,使用场景为:函数的功能比较单一,且只使用一次,写方法名称调用又觉得太麻烦,经常与filter、map、reduce等函数合用
filter: 一个具有过滤功能的函数,通常是将一个序列中的值丢给一个func函数,且当func函数判断为真时,才将值写入到一个元组中,等循环遍历完整个序列后,会返回一 个经过过滤后的元组
map: 和filter功能相似,唯一不同的是,map中的func函数是一个执行一系列操作的功能函数,当循环遍历完整个序列后,会返回一个经一系列操作过后的元组
reduce: 函数的写法和map、filter完全一样,但是调用方法却完全不相同。它是将一个序列的第一个和第二个值进行操作,并将操作后所得到的值再与第三个值进行操作,以此遍历整个序列,最终返回的是一个值(而不map、filter一样返回元组)