zl程序教程

您现在的位置是:首页 >  后端

当前栏目

python中的reduce内建函数使用方法指南

Python方法 使用 指南 reduce 内建函数
2023-06-13 09:15:44 时间

官方解释:

Applyfunctionoftwoargumentscumulativelytotheitemsofiterable,fromlefttoright,soastoreducetheiterabletoasinglevalue.Forexample,reduce(lambdax,y:x+y,[1,2,3,4,5])calculates((((1+2)+3)+4)+5).Theleftargument,x,istheaccumulatedvalueandtherightargument,y,istheupdatevaluefromtheiterable.Iftheoptionalinitializerispresent,itisplacedbeforetheitemsoftheiterableinthecalculation,andservesasadefaultwhentheiterableisempty.Ifinitializerisnotgivenanditerablecontainsonlyoneitem,thefirstitemisreturned.Roughlyequivalentto:

意思就是说:将一个可迭代的对象应用到一个带有两个参数的方法上,我们称之为appFun,遍历这个可迭代对象,将其中的元素依次作为appFun的参数,但这个函数有两个参数,作为哪个参数呢?有这样的规则,看一下下面reduce方法的实现,有三个参数,第一个参数就是上面说的appFun,第二个参数就是那个可迭代的对象,而第三个呢?当调用reduce方法的时候给出了initializer这个参数,那么第一次调用appFun的时候这个参数值就作为第一个参数,而可迭代对象的元素依次作为appFun的第二个参数;如果调用reduce的时候没有给出initializer这个参数,那么第一次调用appFun的时候,可迭代对象的第一个元素就作为appFun的第一个元素,而可迭代器的从第二个元素到最后依次作为appFun的第二个参数,除第一次调用之外,appFun的第一个参数就是appFun的返回值了。例如reduce(lambdax,y:x+y,[1,2,3,4,5]),计算1到5的和,因为没有给定initializer参数,所以第一次调用x+y时,x=1,即列表的第一个元素,y=2,即列表的第二个元素,之后返回的1+2的结果作为第二次调用x+y中的x,即上一次的结果,y=2,即第二个元素,依次类推,知道得到1+2+3+4+5的结果。

这样看来,其实下面的代码定义是有一点问题,我们在程序中调用这段代码reduce(lambdax,y:x+y,[1,2,3,4,5]),得到的结果为16,而正确的结果为15,问题在于如果集合不是以0开始,那么按照如下代码,第一次调用x=1,即第一个元素,y也是等于1,也是第一个元素,而正确的y应该是2。所以真正的reduce方法应该和下面的例子是有差别的。

defreduce(function,iterable,initializer=None):
it=iter(iterable)
ifinitializerisNone:
try:
initializer=next(it)
exceptStopIteration:
raiseTypeError("reduce()ofemptysequencewithnoinitialvalue")
accum_value=initializer
forxiniterable:
accum_value=function(accum_value,x)
returnaccum_value

那么reduce函数能做什么,什么情况下要用reduce呢,看下面的例子:

例如上面的例子,实现一个整形集合的累加。假设lst=[1,2,3,4,5],实现累加的方式有很多:

第一种:用sum函数

sum(lst)

 
第二种:循环方式。

defcustomer_sum(lst):
result=0
forxinlst:
result+=x
returnresult

#或者
defcustomer_sum(lst):
result=0
whilelst:
temp=lst.pop(0)
result+=temp
returnresult

if__name__=="__main__":
lst=[1,2,3,4,5]
printcustomer_sum(lst)

第三种:递推求和

defadd(lst,result):
iflst:
temp=lst.pop(0)
temp+=result
returnadd(lst,temp)
else:
returnresult

if__name__=="__main__":
lst=[1,2,3,4,5]
printadd(lst,0)

第四种:reduce方式

lst=[1,2,3,4,5]
printreduce(lambdax,y:x+y,lst)
#这种方式用lambda表示当做参数,因为没有提供reduce的第三个参数,所以第一次执行时x=1,y=2,第二次x=1+2,y=3,即列表的第三个元素


#或者
lst=[1,2,3,4,5]
printreduce(lambdax,y:x+y,lst,0)
#这种方式用lambda表示当做参数,因为指定了reduce的第三个参数为0,所以第一次执行时x=0,y=1,第二次x=0+1,y=2,即列表的第二个元素,
假定指定reduce的第三个参数为100,那么第一次执行x=100,y仍然是遍历列表的元素,最后得到的结果为115



#或者
defadd(x,y):
returnx+y

printreduce(add,lst)
#与方式1相同,只不过把lambda表达式换成了自定义函数

#或者
defadd(x,y):
returnx+y

printreduce(add,lst,0)
#与方式2相同,只不过把lambda表达式换成了自定义函数

 
再举一个例子:有一个序列集合,例如[1,1,2,3,2,3,3,5,6,7,7,6,5,5,5],统计这个集合所有键的重复个数,例如1出现了两次,2出现了两次等。大致的思路就是用字典存储,元素就是字典的key,出现的次数就是字典的value。方法依然很多

第一种:for循环判断

defstatistics(lst):
dic={}
forkinlst:
ifnotkindic:
dic[k]=1
else:
dic[k]+=1
returndic

lst=[1,1,2,3,2,3,3,5,6,7,7,6,5,5,5]
print(statistics(lst))

第二种:比较取巧的,先把列表用set方式去重,然后用列表的count方法

defstatistics2(lst):
m=set(lst)
dic={}
forxinm:
dic[x]=lst.count(x)

returndic

lst=[1,1,2,3,2,3,3,5,6,7,7,6,5,5,5]
printstatistics2(lst)

第三种:用reduce方式

defstatistics(dic,k):
ifnotkindic:
dic[k]=1
else:
dic[k]+=1
returndic

lst=[1,1,2,3,2,3,3,5,6,7,7,6,5,5,5]
printreduce(statistics,lst,{})
#提供第三个参数,第一次,初始字典为空,作为statistics的第一个参数,然后遍历lst,作为第二个参数,然后将返回的字典集合作为下一次的第一个参数

或者
d={}
d.extend(lst)
printreduce(statistics,d)
#不提供第三个参数,但是要在保证集合的第一个元素是一个字典对象,作为statistics的第一个参数,遍历集合依次作为第二个参数

通过上面的例子发现,凡是要对一个集合进行操作的,并且要有一个统计结果的,能够用循环或者递归方式解决的问题,一般情况下都可以用reduce方式实现。

reduce函数真是“一位好同志啊”!