是否有更简洁,高效或简单的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)
答案 0 :(得分:157)
不使用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)
在以下配置中:
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 | -------+-----------+-----------+-----------+-----------+ A 20.8 µs 13.3 µs 22.6 µs 39.6 µs B 106 µs 95.3 µs 5.92 µs 26.1 µs C 4.34 ms 3.51 ms 16.7 µs 38.9 µs D 46.6 ms 38.5 ms 180 µs 216 µs
结果:np.prod
是最快的,如果您使用np.array
作为数据结构(小数组为18x,大数组为250x)
使用python 3.3.2:
| 1 | 2 | 3 | 4 | -------+-----------+-----------+-----------+-----------+ A 23.6 µs 12.3 µs 68.6 µs 84.9 µs B 133 µs 107 µs 7.42 µs 27.5 µs C 4.79 ms 3.74 ms 18.6 µs 40.9 µs D 48.4 ms 36.8 ms 187 µs 214 µs
python 3慢了吗?
答案 1 :(得分:44)
reduce(lambda x, y: x * y, list, 1)
答案 2 :(得分:38)
如果您的列表中只有数字:
from numpy import prod
prod(list)
编辑:正如@ off99555所指出的,这对大整数结果不起作用,在这种情况下,它返回类型为numpy.int64
的结果,而Ian Clelland的解决方案基于{{1} } operator.mul
适用于大整数结果,因为它返回reduce
。
答案 3 :(得分:17)
import operator
reduce(operator.mul, list, 1)
答案 4 :(得分:15)
好吧,如果你真的想让它成为一行而不进行任何你可以做的事情:
eval('*'.join(str(item) for item in list))
但不要。
答案 5 :(得分:14)
我记得有一些关于comp.lang.python的讨论(对不起,现在懒得生成指针),结论是你的原始product()
定义是最Pythonic 。
请注意,建议不是每次都要编写for循环,而是编写一次函数(每种类型的减少)并根据需要调用它!调用约简函数非常Pythonic - 它与生成器表达式很好地协同工作,自从成功引入sum()
以来,Python不断发展越来越多的内置约简函数 - any()
和all()
是最新的加法...
这个结论有点官方 - reduce()
来自Python 3.0内置的removed,说:
“如果确实需要,请使用
functools.reduce()
;但是,99%的时间显式for循环更具可读性。”
另请参阅The fate of reduce() in Python 3000以获取Guido的支持报价(以及阅读该博客的Lispers的一些支持性评论)。
P.S。如果您需要product()
组合词,请参阅math.factorial()
(新2.6)。
答案 6 :(得分:7)
这个答案的目的是提供一个在某些情况下有用的计算 - 即当a)有大量的值乘以使最终产品可能非常大或极小时,和b)你并不真正关心确切的答案,而是拥有许多序列,并且希望能够根据每个产品的顺序对它们进行订购。
如果要将列表的元素相乘,其中l是列表,则可以执行以下操作:
import math
math.exp(sum(map(math.log, l)))
现在,这种方法不像
那样可读from operator import mul
reduce(mul, list)
如果你是一个不熟悉reduce()的数学家,反之亦然,但我不建议在正常情况下使用它。它的可读性也低于问题中提到的product()函数(至少对于非数学家而言)。
但是,如果您遇到风险下溢或溢出的情况,例如
>>> reduce(mul, [10.]*309)
inf
你的目的是比较不同序列的产品,而不是知道产品是什么,然后
>>> sum(map(math.log, [10.]*309))
711.49879373515785
是要走的路,因为实际上不可能出现这种方法会溢出或下溢的现实问题。 (计算结果越大,如果 计算它,产品就越大。)
答案 7 :(得分:7)
从Python 3.8
开始,prod
函数已包含在标准库的math
模块中:
math.prod(iterable,*,start = 1)
返回一个start
值(默认值:1)乘以一个可迭代数字的乘积:
import math
math.prod([2, 3, 4]) # 24
请注意,如果iterable为空,则会产生1
(或start
值(如果提供))。
答案 8 :(得分:2)
我很惊讶没有人建议将itertools.accumulate
与operator.mul
一起使用。这避免了使用reduce
,这对于Python 2和3来说是不同的(由于Python 3需要functools
导入),而且被认为是非pythonic by Guido van Rossum himself:
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
答案 9 :(得分:1)
一种选择是使用numba
和@jit
or @njit
decorator。我还对您的代码进行了一两次小的调整(至少在Python 3中,“列表”是不应用作变量名的关键字):
@njit
def njit_product(lst):
p = lst[0] # first element
for i in lst[1:]: # loop over remaining elements
p *= i
return p
出于计时目的,您需要先运行一次以使用numba编译函数。通常,该函数将在首次调用时进行编译,然后在内存中调用(更快)。
njit_product([1, 2]) # execute once to compile
现在,当您执行代码时,它将与函数的编译版本一起运行。我使用Jupyter笔记本和%timeit
魔术功能为它们计时:
product(b) # yours
# 32.7 µs ± 510 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
njit_product(b)
# 92.9 µs ± 392 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
请注意,在运行Python 3.5的计算机上,原生Python for
循环实际上是最快的。在使用Jupyter笔记本电脑和%timeit
魔术功能来测量数字装饰性能时,这里可能会有一个技巧。我不确定上述时间是否正确,因此建议您在系统上试用一下,看看numba是否可以提高性能。
答案 10 :(得分:0)
我发现最快的方法是使用while:
mysetup = '''
import numpy as np
from find_intervals import return_intersections
'''
# code snippet whose execution time is to be measured
mycode = '''
x = [4,5,6,7,8,9,10]
prod = 1
i = 0
while True:
prod = prod * x[i]
i = i + 1
if i == len(x):
break
'''
# timeit statement for while:
print("using while : ",
timeit.timeit(setup=mysetup,
stmt=mycode))
# timeit statement for mul:
print("using mul : ",
timeit.timeit('from functools import reduce;
from operator import mul;
c = reduce(mul, [4,5,6,7,8,9,10])'))
# timeit statement for mul:
print("using lambda : ",
timeit.timeit('from functools import reduce;
from operator import mul;
c = reduce(lambda x, y: x * y, [4,5,6,7,8,9,10])'))
时间是:
>>> using while : 0.8887967770060641
>>> using mul : 2.0838719510065857
>>> using lambda : 2.4227715369997895
答案 11 :(得分:0)
我已经用perfplot(我的一个小项目)测试了各种解决方案,发现了
numpy.prod(lst)
到目前为止,是最快的解决方案(如果列表不是很短)。
用于复制情节的代码:
import perfplot
import numpy
from operator import mul
from functools import reduce
from itertools import accumulate
def reduce_lambda(lst):
return reduce(lambda x, y: x * y, lst)
def reduce_mul(lst):
return reduce(mul, lst)
def forloop(lst):
r = 1
for x in lst:
r *= x
return r
def numpy_prod(lst):
return numpy.prod(lst)
def itertools_accumulate(lst):
for value in accumulate(lst, mul):
pass
return value
perfplot.show(
setup=numpy.random.rand,
kernels=[
reduce_lambda,
reduce_mul,
forloop,
numpy_prod,
itertools_accumulate,
],
n_range=[2**k for k in range(15)],
xlabel='len(a)',
logx=True,
logy=True,
)
答案 12 :(得分:0)
OP的Python 3测试结果:(每次3个最好)
with lambda: 18.978000981995137
without lambda: 8.110567473006085
for loop: 10.795806062000338
with lambda (no 0): 26.612515013999655
without lambda (no 0): 14.704098362999503
for loop (no 0): 14.93075215499266
答案 13 :(得分:0)
我不确定最快的方法,但这里是获取任何集合的产品而不导入任何库或模块的短代码。
eval('*'.join(map(str,l)))
答案 14 :(得分:-2)
代码如下:
product = 1 # Set product to 1 because when you multiply it you don't want you answer to always be 0
my_list = list(input("Type in a list: ").split(", ")) # When input, the data is a string, so you need to convert it into a list and split it to make it a list.
for i in range(0, len(my_list)):
product *= int(my_list[i])
print("The product of all elements in your list is: ", product)
答案 15 :(得分:-3)
这也可以作弊
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]