详细分析python3的reduce函数


Posted in Python onDecember 05, 2017

reduce() 函数在 python 2 是内置函数, 从python 3 开始移到了 functools 模块。

官方文档是这样介绍的

reduce(...)
reduce(function, sequence[, initial]) -> value

Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5). If initial is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.

从左到右对一个序列的项累计地应用有两个参数的函数,以此合并序列到一个单一值。

例如,reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) 计算的就是((((1+2)+3)+4)+5)。

如果提供了 initial 参数,计算时它将被放在序列的所有项前面,如果序列是空的,它也就是计算的默认结果值了

嗯, 这个文档其实不好理解。看了还是不懂。 序列 其实就是python中 tuple list dictionary string 以及其他可迭代物,别的编程语言可能有数组。

reduce 有 三个参数

function 有两个参数的函数, 必需参数
sequence tuple ,list ,dictionary, string等可迭代物,必需参数
initial 初始值, 可选参数

reduce的工作过程是 :在迭代sequence(tuple ,list ,dictionary, string等可迭代物)的过程中,首先把 前两个元素传给 函数参数,函数加工后,然后把得到的结果和第三个元素作为两个参数传给函数参数, 函数加工后得到的结果又和第四个元素作为两个参数传给函数参数,依次类推。 如果传入了 initial 值, 那么首先传的就不是 sequence 的第一个和第二个元素,而是 initial值和 第一个元素。经过这样的累计计算之后合并序列到一个单一返回值

reduce 代码举例,使用REPL演示

>>> def add(x, y):
...  return x+y
...
>>> from functools import reduce
>>> reduce(add, [1,2,3,4])
>>>

上面这段 reduce 代码,其实就相当于 1 + 2 + 3 + 4 = 10, 如果把加号改成乘号, 就成了阶乘了
当然 仅仅是求和的话还有更简单的方法,如下

>>> sum([1,2,3,4])
10
>>>

很多教程只讲了一个加法求和,太简单了,对新手加深理解还不够。下面讲点更深入的例子

还可以把一个整数列表拼成整数,如下

>>> from functools import reduce
>>> reduce(lambda x, y: x * 10 + y, [1 , 2, 3, 4, 5])
12345
>>>

对一个复杂的sequence使用reduce ,看下面代码,更多的代码不再使用REPL, 使用编辑器编写

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)

这段代码会出错,看下图的执行过程

详细分析python3的reduce函数

所以代码需要修改

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 有三个参数, 第三个参数是初始值的意思,是可有可无的参数。

修改之后就不出错了,流程如下

详细分析python3的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模块中

Python 相关文章推荐
Python实现简单的文本相似度分析操作详解
Jun 16 Python
python买卖股票的最佳时机(基于贪心/蛮力算法)
Jul 05 Python
Python 使用 PyMysql、DBUtils 创建连接池提升性能
Aug 14 Python
Django对models里的objects的使用详解
Aug 17 Python
python并发编程多进程 互斥锁原理解析
Aug 20 Python
pytorch中的inference使用实例
Feb 20 Python
Python3 mmap内存映射文件示例解析
Mar 23 Python
详解Python 中的容器 collections
Aug 17 Python
如何使用python-opencv批量生成带噪点噪线的数字验证码
Dec 21 Python
python爬虫scrapy基本使用超详细教程
Feb 20 Python
Python爬虫之爬取哔哩哔哩热门视频排行榜
Apr 28 Python
Python使用Opencv打开笔记本电脑摄像头报错解问题及解决
Jun 21 Python
Python数据可视化正态分布简单分析及实现代码
Dec 04 #Python
Python编程实现二分法和牛顿迭代法求平方根代码
Dec 04 #Python
Python编程给numpy矩阵添加一列方法示例
Dec 04 #Python
Python实现返回数组中第i小元素的方法示例
Dec 04 #Python
Python实现基本数据结构中队列的操作方法示例
Dec 04 #Python
Python numpy生成矩阵、串联矩阵代码分享
Dec 04 #Python
Python内置函数—vars的具体使用方法
Dec 04 #Python
You might like
PHP 伪静态隐藏传递参数名的四种方法
2010/02/22 PHP
php笔记之:数据类型与常量的使用分析
2013/05/14 PHP
CodeIgniter基本配置详细介绍
2013/11/12 PHP
php使用curl访问https示例分享
2014/01/17 PHP
php switch语句多个值匹配同一代码块应用示例
2014/07/29 PHP
js中top/parent/frame概述及案例应用
2013/02/06 Javascript
jQuery 遍历-nextUntil()方法以及prevUntil()方法的使用介绍
2013/04/26 Javascript
javascript在myeclipse中报错的解决方法
2013/10/29 Javascript
js/jquery解析json和数组格式的方法详解
2014/01/09 Javascript
解决jquery版本冲突的有效方法
2014/09/02 Javascript
基于jquery实现等比缩放图片
2014/12/03 Javascript
angularjs的一些优化小技巧
2014/12/06 Javascript
jQuery实现非常实用漂亮的select下拉菜单选择效果
2015/11/06 Javascript
AngularJS 让人爱不释手的八种功能
2016/03/23 Javascript
文本框只能输入数字的js代码(含小数点)
2016/07/10 Javascript
vue实现个人信息查看和密码修改功能
2018/05/06 Javascript
Vue.use源码学习小结
2018/06/20 Javascript
vue-vuex中使用commit提交mutation来修改state的方法详解
2018/09/16 Javascript
Vue axios全局拦截 get请求、post请求、配置请求的实例代码
2018/11/28 Javascript
原生JavaScript实现滑动拖动验证的示例代码
2019/12/06 Javascript
Pyspider中给爬虫伪造随机请求头的实例
2018/05/07 Python
pandas 条件搜索返回列表的方法
2018/10/30 Python
python实现超级马里奥
2020/03/18 Python
python如何实现递归转非递归
2021/02/25 Python
html5简介及新增功能介绍
2020/05/18 HTML / CSS
英国在线珠宝店:The Jewel Hut
2017/03/20 全球购物
澳大利亚墨尔本的在线时装店:LORETA
2018/09/14 全球购物
英国最大的在线照明商店:Litecraft
2020/08/31 全球购物
学前班教师的自我鉴定
2013/12/05 职场文书
银行领导证婚词
2014/01/11 职场文书
学校读书活动总结
2014/06/30 职场文书
滞留工资返还协议书
2014/10/19 职场文书
机动车交通事故协议书
2015/01/29 职场文书
考研经验交流会策划书
2015/11/02 职场文书
2019年励志签名:致拼搏路上的自己
2019/10/11 职场文书
详解SQL的窗口函数
2022/04/21 Oracle