我最近开始学习函数式编程,并在尝试计算一个类的测验平均值时提出了这个例子。
我提出的例子是:
scores = [90, 91, 92, 94, 95, 96, 97, 99, 100]
def add(num1, num2):
'''returns the sum of the parameters'''
return num1 + num2
import operator
timeit reduce(add, scores) / len(scores) #--> 1000000 loops, best of 3: 799 ns per loop
timeit sum(scores) / len(scores) #--> 1000000 loops, best of 3: 207 ns per loop
timeit reduce(operator.add, scores) / len(scores) #--> 1000000 loops, best of 3: 485 ns per loop
在上面的例子中,似乎使用更高阶函数几乎要慢4倍。
所以我的问题是,何时是使用更高阶函数的好时机,因为上面的例子显然不是?
答案 0 :(得分:5)
reduce()
才有意义,而不是当您已经拥有一个不仅优于reduce()
的高度优化的库函数时小名单,但大幅在较大的名单上胜过它。
reduce()
为您提供了创建任意折叠的灵活性,但这种灵活性是以一些性能开销为代价的,特别是在大多数基本功能结构被认为略微偏离主流的语言中。
Python具有“功能性”,因为它具有一流的功能,但它主要不是一种功能语言。它为循环中使用提供了丰富的迭代器供应,并具有各种语言功能,使得显式循环易于编写,但并不专注于递归定义的列表操作(尽管它确实允许它们在有限的程度上 - 缺乏TCO例如,我可以直接在Python中解释我的Erlang或Guile代码,但确实可以让我灵活地执行benchmark competing approaches that adhere to similar interfaces}之类的操作。
答案 1 :(得分:2)
除了设置性能问题之外,我不得不这样说:使用sum()
时没有任何问题,而且风格上你应选择sum()
结束reduce()
! reduce()
更通用,因此可用于编写其他减少而不仅仅是求和。 sum()
是一种常见的缩减,它具有自己的名称和定义。
如果你看一下函数式编程语言,你会发现它们有很多用于处理序列的通用实用函数库,比如Haskell' Data.List
或Scheme' {{3} }。这些库中的函数的 lot 可以用其他函数编写;例如,Haskell中的map
函数可以用foldr
(类似于reduce()
)来编写:
map :: (a -> b) -> [a] -> [b]
map f = foldr go []
where f a bs = f a : bs
但没有人认为foldr
因此map
不必要或需要避免。相反,像foldr
或reduce()
这样的更一般的操作被视为构建块,以构建更专业的函数,使程序更易于编写和理解。
reduce()
和sum()
属于同一种关系。 reduce()
是您在没有像sum()
这样的功能时可以使用的构建基块。
答案 2 :(得分:1)
代替总和?从不。
但是,通过自定义方法进行聚合时,减少调用将是一种方法。
例如product
可以定义为:
product = lambda iterable: reduce(operator.mul, iterable)
同样sum
在C。
答案 3 :(得分:0)
reduce
和sum
做了很多不同的事情。考虑像&#34这样的问题;我有一个嵌套字典......
d = {'foo': {'bar': {'baz': 'qux'}}}
我希望获得与密钥列表相关联的值:['foo', 'bar', 'baz']
"。这个可以调用reduce
(如果你是一个函数式编程人员):
>>> reduce(lambda subdict, k: subdict[k], ['foo', 'bar', 'baz'], d)
'qux'
注意,您无法使用sum
执行此操作。只是汇总是一个简单的例子,用于显示减少发生的事情(因为你可以用括号写出来,大多数程序员都熟悉括号组的数学运算)。