返回列表的产品

Sim*_*ins 150 python

是否有更简洁,高效或简单的pythonic方式来执行以下操作?

def product(list):
    p = 1
    for i in list:
        p *= i
    return p
Run Code Online (Sandbox Code Playgroud)

编辑:

我实际上发现这比使用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())
Run Code Online (Sandbox Code Playgroud)

给我

('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)
Run Code Online (Sandbox Code Playgroud)

Rug*_*rra 159

不使用lambda:

from operator import mul
reduce(mul, list, 1)
Run Code Online (Sandbox Code Playgroud)

它更好更快.用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)
Run Code Online (Sandbox Code Playgroud)

在以下配置中:

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
Run Code Online (Sandbox Code Playgroud)

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慢了吗?

  • 请注意,您必须从Python 3中的`functools`模块导入`reduce`操作符.来自functools import reduce`的IE`. (6认同)
  • 可能的原因:(1)Python 3`int`是Python 2`long`.Python 2将使用"int"直到它溢出32位; Python 3从一开始就会使用"long".(2)Python 3.0是一个"概念证明".尽快升级到3.1! (3认同)
  • 非常有趣,谢谢。知道为什么 python 3 可能会更慢吗? (2认同)

Joh*_*rra 45

reduce(lambda x, y: x * y, list, 1)
Run Code Online (Sandbox Code Playgroud)

  • 你必须从functools import reduce`导入它才能使它在Python 3中运行. (6认同)
  • +1但请参阅@ wiso关于`operator.mul`的答案,以获得更好的方法. (3认同)
  • operator.mul是一个函数,因此不仅可以替换x*y,还可以替换整个lambda表达式(即`reduce`的第一个参数) (2认同)

And*_*ner 42

如果您的列表中只有数字:

from numpy import prod
prod(list)
Run Code Online (Sandbox Code Playgroud)

编辑:正如@ off99555所指出的,这不适用于大整数结果,在这种情况下,它返回类型的结果,numpy.int64而Ian Clelland的解决方案基于operator.mulreduce适用于大整数结果,因为它返回long.


Ian*_*and 18

import operator
reduce(operator.mul, list, 1)
Run Code Online (Sandbox Code Playgroud)

  • 如果列表可能为空,则最后一个参数是必需的,否则它将抛出TypeError异常.当然,有时会出现例外情况. (9认同)
  • 对我而言,它返回0而没有该参数,因此您还可以认为有必要强制执行空产品约定. (2认同)

sem*_*lon 16

好吧,如果你真的想让它成为一行而不导入你可以做的任何东西:

eval('*'.join(str(item) for item in list))
Run Code Online (Sandbox Code Playgroud)

但不要.


Ben*_*kin 15

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

请注意,建议不是每次都要编写for循环,而是编写一次函数(每种类型的减少)并根据需要调用它!调用缩减函数非常Pythonic - 它与生成器表达式很好地协同工作,并且自成功引入以来sum(),Python不断增加越来越多的内置还原功能 - any()并且all()是最新增加的......

这个结论有点官方 - 从Python 3.0中的内置函数reduce()删除,说:

" functools.reduce()如果你真的需要它,请使用它;但是,99%的时间显式循环更具可读性."

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

PS如果偶然需要product()组合,请参阅math.factorial()(新2.6).

  • +1对于Python社区中普遍存在的情绪的准确(据我所知)的说法 - 虽然我肯定更倾向于反对在这种情况下流行的情绪,但最好还是知道它们是什么.另外,我喜欢LtU中不支持的Lispers(我猜是其中之一).:-) (2认同)

Xav*_*hot 11

从开始Python 3.8prod函数已包含math在标准库的模块中:

math.prod(iterable,*,start = 1)

它返回一个start值(默认值:1)乘以一个可迭代数字的乘积:

import math

math.prod([2, 3, 4]) # 24
Run Code Online (Sandbox Code Playgroud)

请注意,如果iterable为空,则将生成1(或start提供值(如果提供))。


gar*_*rob 7

这个答案的目的是提供一个在某些情况下有用的计算 - 即当a)有大量的值乘以使最终产品可能非常大或极小时,b)你不要我真的关心确切的答案,但有许多序列,并希望能够根据每个产品订购它们.

如果要将列表的元素相乘,其中l是列表,则可以执行以下操作:

import math
math.exp(sum(map(math.log, l)))
Run Code Online (Sandbox Code Playgroud)

现在,这种方法不像以下那样可读

from operator import mul
reduce(mul, list)
Run Code Online (Sandbox Code Playgroud)

如果你是一个不熟悉reduce()的数学家,反之亦然,但我不建议在正常情况下使用它.它的可读性也低于问题中提到的product()函数(至少对于非数学家而言).

但是,如果您遇到风险下溢或溢出的情况,例如

>>> reduce(mul, [10.]*309)
inf
Run Code Online (Sandbox Code Playgroud)

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

>>> sum(map(math.log, [10.]*309))
711.49879373515785
Run Code Online (Sandbox Code Playgroud)

是要走的路,因为这种方法几乎不可能出现现实世界的问题.(该计算的更大的结果是,较大的产品是,如果你计算.)


Nic*_*mer 5

我用perfplot(我的一个小项目)测试了各种解决方案,发现

numpy.prod(lst)
Run Code Online (Sandbox Code Playgroud)

迄今为止最快的解决方案(如果列表不是很短)。

在此处输入图片说明


复制剧情的代码:

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,
    )
Run Code Online (Sandbox Code Playgroud)