Python 一行求和实现?
首先,我问这个问题纯粹是出于好奇,想看看大家的单行代码技巧。sum()
这个函数仍然是计算列表中对象总和的最佳选择。
不过正如我所说,我只是出于好奇:有没有办法在一行代码里,不用sum()
函数来计算一个list
中的对象总和呢?假设这个列表是range(0, 100)
。
我完全不知道该怎么做,但因为Python真的很棒而且灵活,所以我相信这是可能的。
3 个回答
Python 可能不是处理递归问题的最佳语言,原因有几个:首先,它不支持尾递归;其次,函数调用的开销很大;再者,递归的深度有限制,不能进行太深的递归;最后,切片操作的复杂度是 O(n)
(这里的 n
是切片中元素的数量)。
不过,你可以用它来写一行代码!
一种方法是不断地取出第一个元素并加到结果中,直到序列用完为止:
>>> sum_func = lambda x: x[0] + sum_func(x[1:]) if x else 0
>>> sum_func(range(100))
4950
这个过程会一直进行,只要 if x
成立(也就是说 x
不是空的)。这种方法暴露了在 Python 中使用递归的所有缺点:对于长度大约为 300 的序列,它会达到递归限制,复杂度是 O(n**2)
,而且相比于内置的 sum
和 reduce
方法,它的速度非常慢。
我们可以通过使用分治法来减轻其中一个缺点:
>>> sum_func = lambda x: sum_func(x[:len(x)//2]) + sum_func(x[len(x)//2:]) if len(x) > 1 else x[0]
>>> sum_func(range(100))
4950
这次它会对列表的两个部分进行递归,从而将递归的深度从 n
降低到 log2(n)
,这样可以处理更长的序列。不过,它的速度并没有比上面的方法快。
当然,还有一种作弊的方法:
>>> from numpy import sum
>>> sum(range(100))
4950
如果你真的想要快速解决这个问题 :-)
你可以用一种函数式的方法,使用 reduce
函数和一个加法函数(比如一个 lambda
表达式 或 operator.add
):
>>> from operator import add
>>> reduce(add, range(0, 100))
4950
(注意,在 Python 3.x 中,你需要先执行 from functools import reduce
。)
根据文档,reduce(function, iterable)
的作用是:
将
function
这个需要两个参数的函数,逐个应用到iterable
中的每个元素上,从左到右进行处理,最终把iterable
简化成一个单一的值。
为了好玩,这里有一个解决方案,完全不需要任何内置函数。它基本上是对 reduce
函数的重新实现,使用了一点点神奇的 lambda 表达式。
>>>>(lambda f: lambda *args: f(f, *args))(lambda self, f, seq, d: d if not seq else f(seq[0], self(self, f, seq[1:], d)))(lambda a,b: a+b, range(100), 0)
4950