Есть ли более лаконичный, эффективный или просто питонический способ сделать следующее?
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)
reduce
ответы поднимают aTypeError
, тогда какfor
ответ цикла возвращает 1. Это ошибка вfor
ответе цикла (произведение пустого списка не больше 1, чем 17 или «броненосец»).list
в качестве имени переменной ...+
для этого типа списка (аналогично для продукта /*
). Теперь я понимаю, что Python динамически типизирован, что усложняет ситуацию, но это решаемая проблема в нормальных языках со статическими системами типов, такими как Haskell. НоPython
только позволяетsum
работать над числами в любом случае, так как,sum(['a', 'b'])
даже не работа, поэтому я еще раз говорю , что0
имеет смыслsum
и1
для продукта.Ответы:
Без использования лямбды:
это лучше и быстрее. С питоном 2.7.5
В следующей конфигурации:
Результаты с питоном 2.7.5
Результат:
np.prod
самый быстрый, если вы используете вnp.array
качестве структуры данных (18x для маленького массива, 250x для большого массива)с питоном 3.3.2:
Python 3 медленнее?
источник
int
- это Python 2long
. Python 2 будет использовать int до тех пор, пока он не переполнится 32 битами; Python 3 будет использовать «long» с самого начала. (2) Python 3.0 был «доказательством концепции». Обновите до 3.1 как можно скорее!reduce
оператор изfunctools
модуля в Python 3. IEfrom functools import reduce
.источник
operator.mul
как лучше это сделать.reduce
)from functools import reduce
чтобы заставить его работать в Python 3.если у вас просто есть номера в вашем списке:
РЕДАКТИРОВАТЬ : как указано @ off99555, это не работает для больших целочисленных результатов, в этом случае он возвращает результат типа, в
numpy.int64
то время как решение Яна Клелленда основано на больших целочисленных результатах,operator.mul
иreduce
работает, потому что оно возвращаетlong
.источник
from numpy import prod; prod(list(range(5,101)))
и он вывел0
, можете ли вы воспроизвести этот результат на Python 3?prod
возвращает результат типаnumpy.int64
в этом случае, и вы получаете переполнение (фактически отрицательное значение) дляrange(5,23)
. Используйте решение @Ian Clelland, основанное наoperator.mul
иreduce
для больших целых чисел (long
в этом случае оно возвращает a, которое, по-видимому, имеет произвольную точность).np.prod(np.arange(5.0,101.0))
егоnp.prod(np.array(range(5,101)).astype(np.float64))
. Обратите внимание, что NumPy используетnp.float64
вместоfloat
. Я не знаю разницу.Хорошо, если вы действительно хотите сделать это одной строкой, не импортируя ничего, что вы могли бы сделать:
Но не надо.
источник
источник
functools.reduce(..)
в python3Начиная
Python 3.8
,prod
функция была включена вmath
модуль в стандартной библиотеке:который возвращает произведение
start
значения (по умолчанию: 1), умноженное на итерируемое число:Обратите внимание, что если итерация пуста, это даст
1
(илиstart
значение, если оно предоставлено).источник
Я помню несколько долгих обсуждений на comp.lang.python (извините, слишком ленив, чтобы создавать указатели сейчас), которые пришли к выводу, что ваше первоначальное
product()
определение является наиболее Pythonic .Обратите внимание, что предложение состоит не в том, чтобы писать цикл for каждый раз, когда вы хотите это сделать, а в том, чтобы написать функцию один раз (для каждого типа сокращения) и вызывать ее при необходимости! Вызов функций редукции очень Pythonic - он прекрасно работает с выражениями-генераторами, и с момента успешного введения
sum()
Python продолжает расти все больше и больше встроенных функций редукции -any()
иall()
является последним дополнением ...Этот вывод является своего рода официальным -
reduce()
был удален из buildins в Python 3.0, говоря:См. Также «Судьба редуцирования () в Python 3000» за цитатой из поддержки Гвидо (и некоторыми менее рецензирующими комментариями Лисперса, читающими этот блог).
PS если случайно вам понадобится
product()
комбинаторика, см.math.factorial()
(Новая 2.6).источник
Цель этого ответа состоит в том, чтобы предоставить расчет, который будет полезен в определенных обстоятельствах, а именно, когда: а) большое количество значений умножается так, что конечный продукт может быть очень большим или очень маленьким, и б) вы не ' Точный ответ действительно важен, но вместо этого имейте несколько последовательностей и хотите иметь возможность упорядочить их по каждому продукту.
Если вы хотите умножить элементы списка, где l - список, вы можете сделать:
Теперь этот подход не так удобен для чтения, как
Если вы математик, который не знаком с методом Reduce (), может быть и обратное, но я бы не советовал использовать его в обычных условиях. Это также менее читабельно, чем функция product (), упомянутая в вопросе (по крайней мере, для нематематиков).
Тем не менее, если вы когда-либо находитесь в ситуации, когда вы рискуете переполнение или переполнение, например, в
и ваша цель состоит в том, чтобы сравнить продукты разных последовательностей, а не узнать, что это за продукты, то
это путь, потому что практически невозможно иметь реальную проблему, в которой вы будете переполнены или переполнены этим подходом. (Чем больше результат этого расчета, тем больше будет продукт, если вы сможете его рассчитать.)
источник
Я протестировал различные решения с помощью perfplot ( мой маленький проект) и обнаружил, что
является на сегодняшний день самым быстрым решением (если список не является очень коротким).
Код для воспроизведения сюжета:
источник
Я удивлен, что никто не предложил использовать
itertools.accumulate
сoperator.mul
. Это позволяет избежать использованияreduce
, которое отличается для Python 2 и 3 (из-заfunctools
импорта, необходимого для Python 3), и, кроме того, сам Гвидо ван Россум считает непитоническим :Пример:
источник
Одним из вариантов является использование
numba
и@jit
или@njit
декоратора . Я также сделал один или два небольших изменения в вашем коде (по крайней мере, в Python 3 «список» - это ключевое слово, которое не должно использоваться для имени переменной):В целях синхронизации вам нужно запустить один раз, чтобы сначала скомпилировать функцию, используя numba. В общем случае функция компилируется при первом вызове, а затем вызывается из памяти (быстрее).
Теперь, когда вы выполните свой код, он будет работать с скомпилированной версией функции. Я рассчитал их, используя блокнот Jupyter и
%timeit
волшебную функцию:Обратите внимание, что на моей машине с Python 3.5 нативный
for
цикл Python был на самом деле самым быстрым. Здесь может быть хитрость, когда дело доходит до измерения производительности, украшенной нумбой, с помощью ноутбуков Jupyter и%timeit
волшебной функции. Я не уверен, что приведенные выше значения времени верны, поэтому я рекомендую попробовать их в своей системе и посмотреть, дает ли numba прирост производительности.источник
Самый быстрый способ, который я нашел, был при использовании while:
и сроки:
источник
Результат Python 3 для тестов OP: (лучший из 3 для каждого)
источник
Это также работает, хотя его обман
источник
print
с возвратом. Кроме того, нет необходимости хранить промежуточные значения в списке, вам просто нужно хранитьp
между итерациями.