你什么时候会使用 reduce() 而不是 sum()?
When would you use reduce() instead of sum()?
我最近开始学习函数式编程,并在尝试计算 class 的测验平均分时想出了这个例子。
我想出的例子是:
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 倍。
所以我的问题是,什么时候是使用高阶函数的好时机,因为上面的例子显然不是?
当您需要对数据列表进行 任意 操作时,reduce()
才有意义,而不是当您已经拥有一个不仅性能优于 reduce()
在小列表上,但 大大地 在大列表上优于它。
reduce()
为您提供了创建任意折叠的灵活性,但这种灵活性是以一些性能开销为代价的,尤其是在大多数基本功能结构被认为略微超出主流的语言中。
Python 是 "functional",因为它具有 first-class 函数,但它主要不是函数式语言。它提供了大量用于循环的迭代器,并具有使显式循环易于编写的各种语言特性,但并不专注于递归定义的列表操作(尽管它确实在有限程度上允许它们——缺乏 TCO阻止我直接在 Python 中解释我的 Erlang 或 Guile 代码,但确实让我可以灵活地做 benchmark competing approaches that adhere to similar interfaces).
之类的事情
代替总和?从来没有。
但是在通过自定义方法进行聚合时,reduce 调用是可行的方法。
例如 product
可以定义为:
product = lambda iterable: reduce(operator.mul, iterable)
另外 sum
在 C 中实现。
reduce
和 sum
做的事情截然不同。考虑一个问题,例如“我有一个嵌套字典......
d = {'foo': {'bar': {'baz': 'qux'}}}
我想获取与键列表关联的值:['foo', 'bar', 'baz']
”。这 可以 调用 reduce
(如果你我是一种函数式编程的人):
>>> reduce(lambda subdict, k: subdict[k], ['foo', 'bar', 'baz'], d)
'qux'
请注意,您不能使用 sum
执行此操作。碰巧求和是一个简单的例子来说明 reduce 发生了什么(因为你可以用括号写出来,而且大多数程序员都熟悉括号如何分组数学运算)。
撇开性能问题不谈,我不得不说:使用 sum()
完全没有错,而且在风格上你 应该 选择 sum()
超过 reduce()
! reduce()
更通用,因此可用于编写其他归约,而不仅仅是求和。 sum()
是一种非常常见的归约,值得拥有自己的名称和定义。
如果您查看函数式编程语言,您会发现例如它们具有用于处理序列的大型通用实用函数库,例如 Haskell 的 Data.List
or Scheme's SRFI-1。这些库中的 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()
之类的功能时可以使用的构建块。
我最近开始学习函数式编程,并在尝试计算 class 的测验平均分时想出了这个例子。
我想出的例子是:
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 倍。
所以我的问题是,什么时候是使用高阶函数的好时机,因为上面的例子显然不是?
reduce()
才有意义,而不是当您已经拥有一个不仅性能优于 reduce()
在小列表上,但 大大地 在大列表上优于它。
reduce()
为您提供了创建任意折叠的灵活性,但这种灵活性是以一些性能开销为代价的,尤其是在大多数基本功能结构被认为略微超出主流的语言中。
Python 是 "functional",因为它具有 first-class 函数,但它主要不是函数式语言。它提供了大量用于循环的迭代器,并具有使显式循环易于编写的各种语言特性,但并不专注于递归定义的列表操作(尽管它确实在有限程度上允许它们——缺乏 TCO阻止我直接在 Python 中解释我的 Erlang 或 Guile 代码,但确实让我可以灵活地做 benchmark competing approaches that adhere to similar interfaces).
之类的事情代替总和?从来没有。
但是在通过自定义方法进行聚合时,reduce 调用是可行的方法。
例如 product
可以定义为:
product = lambda iterable: reduce(operator.mul, iterable)
另外 sum
在 C 中实现。
reduce
和 sum
做的事情截然不同。考虑一个问题,例如“我有一个嵌套字典......
d = {'foo': {'bar': {'baz': 'qux'}}}
我想获取与键列表关联的值:['foo', 'bar', 'baz']
”。这 可以 调用 reduce
(如果你我是一种函数式编程的人):
>>> reduce(lambda subdict, k: subdict[k], ['foo', 'bar', 'baz'], d)
'qux'
请注意,您不能使用 sum
执行此操作。碰巧求和是一个简单的例子来说明 reduce 发生了什么(因为你可以用括号写出来,而且大多数程序员都熟悉括号如何分组数学运算)。
撇开性能问题不谈,我不得不说:使用 sum()
完全没有错,而且在风格上你 应该 选择 sum()
超过 reduce()
! reduce()
更通用,因此可用于编写其他归约,而不仅仅是求和。 sum()
是一种非常常见的归约,值得拥有自己的名称和定义。
如果您查看函数式编程语言,您会发现例如它们具有用于处理序列的大型通用实用函数库,例如 Haskell 的 Data.List
or Scheme's SRFI-1。这些库中的 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()
之类的功能时可以使用的构建块。