Возврат продукта из списка - PullRequest
139 голосов
/ 20 января 2010

Есть ли более лаконичный, эффективный или просто питонический способ сделать следующее?

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

EDIT:

Я на самом деле считаю, что это немного быстрее, чем при использовании 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)

Ответы [ 13 ]

1 голос
/ 07 января 2019

Один из вариантов - использовать numba и декоратор @jit или @njit . Я также сделал один или два небольших изменения в вашем коде (по крайней мере, в 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 прирост производительности.

0 голосов
/ 20 сентября 2018

Самый быстрый способ, который я нашел, был при использовании 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
0 голосов
/ 28 февраля 2013

Это также работает, хотя его обман

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]    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...