返回列表的产品

有没有一个更简洁,高效或简单pythonic的方式来做到以下几点?

def product(list): p = 1 for i in list: p *= i return p 

编辑:

我实际上发现这比使用operator.mul稍微快一些:

 from operator import mul # from functools import reduce # python3 compatibility def with_lambda(list): reduce(lambda x, y: x * y, list) def without_lambda(list): reduce(mul, list) def forloop(list): r = 1 for x in list: r *= x return r import timeit a = range(50) b = range(1,50)#no zero t = timeit.Timer("with_lambda(a)", "from __main__ import with_lambda,a") print("with lambda:", t.timeit()) t = timeit.Timer("without_lambda(a)", "from __main__ import without_lambda,a") print("without lambda:", t.timeit()) t = timeit.Timer("forloop(a)", "from __main__ import forloop,a") print("for loop:", t.timeit()) t = timeit.Timer("with_lambda(b)", "from __main__ import with_lambda,b") print("with lambda (no 0):", t.timeit()) t = timeit.Timer("without_lambda(b)", "from __main__ import without_lambda,b") print("without lambda (no 0):", t.timeit()) t = timeit.Timer("forloop(b)", "from __main__ import forloop,b") print("for loop (no 0):", t.timeit()) 

给我

 ('with lambda:', 17.755449056625366) ('without lambda:', 8.2084708213806152) ('for loop:', 7.4836349487304688) ('with lambda (no 0):', 22.570688009262085) ('without lambda (no 0):', 12.472226858139038) ('for loop (no 0):', 11.04065990447998) 

不使用lambda:

 from operator import mul reduce(mul, list, 1) 

这是更好,更快。 用python 2.7.5

 from operator import mul import numpy as np import numexpr as ne # from functools import reduce # python3 compatibility a = range(1, 101) %timeit reduce(lambda x, y: x * y, a) # (1) %timeit reduce(mul, a) # (2) %timeit np.prod(a) # (3) %timeit ne.evaluate("prod(a)") # (4) 

在以下configuration中:

 a = range(1, 101) # A a = np.array(a) # B a = np.arange(1, 1e4, dtype=int) #C a = np.arange(1, 1e5, dtype=float) #D 

结果与python 2.7.5


        |  1 |  2 |  3 |  4 |
 ------- + ----------- ----------- + + ----------- ------ + ----- +
  20.8μs13.3μs22.6μs39.6μs     
  B106μs95.3μs5.92μs26.1μs
  C 4.34毫秒3.51毫秒16.7微秒38.9微秒
  D 46.6毫秒38.5毫秒180微秒216微秒

结果: np.prod是最快的,如果你使用np.array作为数据结构(小数组为18x,大数组为250x)

用python 3.3.2:


        |  1 |  2 |  3 |  4 |
 ------- + ----------- ----------- + + ----------- ------ + ----- +
  23.6μs12.3μs68.6μs84.9μs     
  B133μs107μs7.42μs27.5μs
  C 4.79 ms 3.74 ms 18.6μs40.9μs
  D 48.4 ms 36.8 ms 187μs214μs

python 3是慢吗?

 reduce(lambda x, y: x * y, list, 1) 

如果你在列表中只有数字:

 from numpy import prod prod(list) 

编辑 :由@ off99555指出,这不适用于大整数结果,在这种情况下,它返回numpy.int64types的结果,而基于operator.mulreduce伊恩克莱兰的解决scheme,因为它返回long整型结果。

 import operator reduce(operator.mul, list, 1) 

我记得有关comp.lang.python的很长时间的讨论(对不起,现在懒得生成指针),结论是你的原始product()定义是Pythonic

请注意,build议不要每次都要写一个for循环,而是写一个函数(每种types的减less)并根据需要调用它! 调用简化函数是Pythonic – 它使用了生成器expression式,并且随着sum()的成功引入,Python不断增长越来越多的内置简化函数 – any()all()是最新的增加…

这个结论还是有点官方的 – 在Python 3.0中, reduce()被从内build中删除 ,他说:

如果你真的需要,可以使用functools.reduce() ;但是,99%的显式for循环更具可读性。

另请参阅Python 3000中reduce()的命运,以获得Guido支持的引用(以及一些Lispers支持阅读该博客的评论)。

PS如果碰巧你需要combinatorics的product() ,请参阅math.factorial() (new 2.6)。

这个答案的目的是提供一个在某些情况下有用的计算 – 即当a)有大量的值被乘以使最终产品可能非常大或非常小时,以及b)不是真正关心确切的答案,而是有一些序列,并希望能够根据每个产品进行sorting。

如果你想乘以列表中的元素,其中l是列表,你可以这样做:

 import math math.exp(sum(map(math.log, l))) 

现在,这个方法不像可读性那么好

 from operator import mul reduce(mul, list) 

如果你是一个不熟悉reduce()的math家,则可能是相反的,但我不build议在正常情况下使用它。 这个问题也比问题中提到的product()函数更不可读(至less对非math家来说)。

但是,如果您曾经处于风险下溢或溢出的情况,例如

 >>> reduce(mul, [10.]*309) inf 

你的目的是比较不同序列的产品,而不是知道产品是什么

 >>> sum(map(math.log, [10.]*309)) 711.49879373515785 

是要走的路,因为实际上不可能有这样一个现实世界的问题,在这个问题上你会用这种方法溢出或者下溢。 (计算结果越大,如果可以计算,产品就越大)。

那么如果你真的想把它做成一行而不input任何你可以做的事情:

 eval('*'.join(str(item) for item in list)) 

但是不要。

我很惊讶没有人build议使用与operator.mul itertools.accumulate 。 这样可以避免使用reduce ,这对于Python 2和Python 3来说是不同的(由于Python 3需要导入functools ),而且被Guido van Rossum本人认为是非pythonic:

 from itertools import accumulate from operator import mul def prod(lst): for value in accumulate(lst, mul): pass return value 

例:

 prod([1,5,4,3,5,6]) # 1800 

这也可以起作用

 def factorial(n): x=[] if n <= 1: return 1 else: for i in range(1,n+1): p*=i x.append(p) print x[n-1]