Есть ли более краткий, эффективный или простой питонический способ сделать следующее?
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)
Ответ 1
Без использования лямбда:
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 медленнее?
Ответ 2
reduce(lambda x, y: x * y, list, 1)
Ответ 3
если у вас просто есть номера в списке:
from numpy import prod
prod(list)
EDIT: как указано в @off99555, это не работает для больших целочисленных результатов, и в этом случае он возвращает результат типа numpy.int64
, а решение Ian Clelland на основе operator.mul
и reduce
работает для больших целых результатов, потому что он возвращает long
.
Ответ 4
import operator
reduce(operator.mul, list, 1)
Ответ 5
Я помню некоторые длительные дискуссии о comp.lang.python(извините, слишком ленив, чтобы создавать указатели сейчас), которые пришли к выводу, что ваше исходное определение product()
является самым Pythonic.
Обратите внимание, что предложение состоит не в том, чтобы писать цикл for каждый раз, когда вы хотите это сделать, а в том, чтобы написать функцию один раз (по типу сокращения) и называть ее по мере необходимости! Вызывающие функции сокращения очень Pythonic - он сладко работает с генераторными выражениями, и с момента успешного внедрения sum()
, Python продолжает все больше и больше встроенных функций сокращения - any()
и all()
являются последними дополнениями...
Этот вывод является официальным официальным - reduce()
был удален из встроенных в Python 3.0, говоря:
"Используйте functools.reduce()
, если вам это действительно нужно, но в 99% случаев явный цикл цикла более читабельен".
См. также Судьба reduce() в Python 3000 для поддержки цитаты из Guido (и несколько менее содержательных комментариев от Lispers, которые гласили, что блог).
P.S. если вам понадобится product()
для комбинаторики, см. math.factorial()
(новый 2.6).
Ответ 6
Цель этого ответа состоит в том, чтобы дать расчет, который полезен в определенных обстоятельствах, а именно когда a) существует большое количество значений, которые умножаются так, что конечный продукт может быть чрезвычайно большим или крайне малым, и b) вам на самом деле не нужен точный ответ, но вместо этого есть несколько последовательностей и вы хотите иметь возможность упорядочивать их на основе каждого продукта.
Если вы хотите размножить элементы списка, где l - список, вы можете сделать:
import math
math.exp(sum(map(math.log, l)))
Теперь этот подход не так читается, как
from operator import mul
reduce(mul, list)
Если вы математик, который не знаком с сокращением(), это может быть наоборот, но я не советую использовать его при обычных обстоятельствах. Это также менее читаемо, чем функция product(), упомянутая в вопросе (по крайней мере, не математикам).
Однако, если вы когда-либо находитесь в ситуации, когда вы рискуете переполнением или переполнением, например, в
>>> reduce(mul, [10.]*309)
inf
и ваша цель - сравнить продукты разных последовательностей, а не знать, что такое продукты, тогда
>>> sum(map(math.log, [10.]*309))
711.49879373515785
- это путь, потому что практически невозможно иметь проблему реального мира, в которой вы бы переполняли или переполняли этот подход. (Чем больше результат этого вычисления, тем больше будет продукт, если вы можете его вычислить.)
Ответ 7
Хорошо, если вы действительно хотели сделать это одной строкой, не импортируя ничего, что могли бы сделать:
eval('*'.join(str(item) for item in list))
Но не надо.
Ответ 8
Я удивлен, что никто не предложил использовать itertools.accumulate
с operator.mul
. Это позволяет избежать использования reduce
, которое отличается для Python 2 и 3 (из-за импорта functools
, требуемого для Python 3), и, кроме того, считается непитоновым самого Guido van Rossum:
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
Это также работает, хотя его обман
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]