原文参考:https://www.cnblogs.com/lonkiss/p/understanding-python-reduce-function.html
描述
reduce() 函数会对参数序列中元素进行累积。
函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果
语法
reduce() 函数语法:
reduce(function, iterable, initializer)
参数
- function -- 有两个参数的函数, 必需参数
- iterable -- tuple ,list ,dictionary, string等可迭代物,必需参数
- initializer -- 初始值, 可选参数
如果提供initial参数,会以sequence中的第一个元素和initial作为参数调用function,否则会以序列sequence中的前两个元素做参数调用function。
返回值
返回函数计算结果。
实例
以下实例展示了 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
reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函数
# 15
在 Python3 中,reduce() 函数已经被从全局名字空间里移除了,它现在被放置在 fucntools 模块里,如果想要使用它,则需要通过引入 functools 模块来调用 reduce() 函数:
使用场景:
- 上面实例中的数组求和
- 字符串反转
from functools import reduce
a = 'password'
result = reduce(lambda x, y: y + x, a)
print(result)
# drowssap
- 把一个整数列表拼成整数
from functools import reduce
reduce(lambda x, y: x * 10 + y, [1 , 2, 3, 4, 5])
# 12345
还有几个例子,玩起来可能又点乱,了解一下:
对一个复杂的sequence使用reduce ,看下面代码:
from functools import reduce
scientists =({'name':'Alan Turing', 'age':105},
{'name':'Dennis Ritchie', 'age':76},
{'name':'John von Neumann', 'age':114},
{'name':'Guido van Rossum', 'age':61})
def reducer(accumulator , value):
sum = accumulator['age'] + value['age']
return sum
total_age = reduce(reducer, scientists)
print(total_age)
这段代码会出错,看下图的执行过程
所以代码需要修改
from functools import reduce
scientists =({'name':'Alan Turing', 'age':105, 'gender':'male'},
{'name':'Dennis Ritchie', 'age':76, 'gender':'male'},
{'name':'Ada Lovelace', 'age':202, 'gender':'female'},
{'name':'Frances E. Allen', 'age':84, 'gender':'female'})
def reducer(accumulator , value):
sum = accumulator + value['age']
return sum
total_age = reduce(reducer, scientists, 0)
print(total_age)
7, 9 行 就是修改 部分。 通过 help(reduce) 查看 文档,
reduce 有三个参数, 第三个参数是初始值的意思,是可有可无的参数。
修改之后就不出错了,流程如下
这个仍然也可以用 sum 来更简单的完成
sum([x['age'] for x in scientists ])
做点更高级的事情,按性别分组
from functools import reduce
scientists =({'name':'Alan Turing', 'age':105, 'gender':'male'},
{'name':'Dennis Ritchie', 'age':76, 'gender':'male'},
{'name':'Ada Lovelace', 'age':202, 'gender':'female'},
{'name':'Frances E. Allen', 'age':84, 'gender':'female'})
def group_by_gender(accumulator , value):
accumulator[value['gender']].append(value['name'])
return accumulator
grouped = reduce(group_by_gender, scientists, {'male':[], 'female':[]})
print(grouped)
输出
{'male': ['Alan Turing', 'Dennis Ritchie'], 'female': ['Ada Lovelace', 'Frances E. Allen']}
可以看到,在 reduce 的初始值参数传入了一个dictionary,, 但是这样写 key 可能出错,还能再进一步自动化,运行时动态插入key
修改代码如下
grouped = reduce(group_by_gender, scientists, collections.defaultdict(list))
当然 先要 import collections 模块
这当然也能用 pythonic way 去解决
import itertools
scientists =({'name':'Alan Turing', 'age':105, 'gender':'male'},
{'name':'Dennis Ritchie', 'age':76, 'gender':'male'},
{'name':'Ada Lovelace', 'age':202, 'gender':'female'},
{'name':'Frances E. Allen', 'age':84, 'gender':'female'})
grouped = {item[0]:list(item[1])
for item in itertools.groupby(scientists, lambda x: x['gender'])}
print(grouped)
再来一个更晦涩难懂的玩法。工作中要与其他人协作的话,不建议这么用,与上面的例子做同样的事,看不懂无所谓
from functools import reduce
scientists =({'name':'Alan Turing', 'age':105, 'gender':'male'},
{'name':'Dennis Ritchie', 'age':76, 'gender':'male'},
{'name':'Ada Lovelace', 'age':202, 'gender':'female'},
{'name':'Frances E. Allen', 'age':84, 'gender':'female'})
grouped = reduce(lambda acc, val: {**acc, **{val['gender']: acc[val['gender']]+ [val['name']]}}, scientists, {'male':[], 'female':[]})
print(grouped)
**acc, **{val['gneder']... 这里使用了 dictionary merge syntax , 从 python 3.5 开始引入, 详情请看 PEP 448 - Additional Unpacking Generalizations 怎么使用可以参考这个 python - How to merge two dictionaries in a single expression? - Stack Overflow
python 社区推荐写可读性好的代码,有更好的选择时不建议用reduce,所以 python 2 中内置的reduce 函数 移到了 functools模块中