Подтвердить что ты не робот

Возврат продукта из списка

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

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)
4b9b3361

Ответ 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]