返回列表的产品
有没有一个更简洁,高效或简单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.int64
types的结果,而基于operator.mul
和reduce
伊恩克莱兰的解决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]