Як я можу помножити всі елементи у списку разом із Python?


204

Мені потрібно написати функцію, яка бере список чисел і множує їх разом. Приклад: [1,2,3,4,5,6]дасть мені 1*2*3*4*5*6. Я справді міг би скористатися вашою допомогою.

Відповіді:


208

Python 3: використання functools.reduce:

>>> from functools import reduce
>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
720

Python 2: використання reduce:

>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
720

Для сумісного з 2 та 3 використанням pip install six, то:

>>> from six.moves import reduce
>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
720

Ви не імпортуєте оператора, тому це рішення трохи компактніше. Цікаво, що швидше.
jheld

30
@jheld: Я присвоїв номери продуктів від 1 до 100. І в python2, і в 3 lambdaв середньому було 0,102 / 1000 повторень, тоді як operator.mulу середньому було 0,009 / 1000 повторень, зробивши operator.mulпорядок швидше.
whereswalden

4
@wordsforthewise, ймовірно, це те, що перехід додаткової функції (лямбда) додає накладні витрати, тоді як operator.mulйде прямо до C.
whereswalden

4
Я дійсно не закликав би .009 на порядок менший ніж .02. Це лише близько половини.
JLH

1
Як і в Python 3.8, це можна зробити просто math.prod([1,2,3,4,5,6]). (вимагає імпорту курсу)
Tomerikoo

168

Ви можете використовувати:

import operator
import functools
functools.reduce(operator.mul, [1,2,3,4,5,6], 1)

Див. reduceТа operator.mulдокументацію для пояснення.

Вам потрібна import functoolsлінія в Python 3+.


32
Зауважте, що в python3 reduce()функція була видалена з глобального простору імен та розміщена в functoolsмодулі. Таким чином , в Python3 вам потрібно сказати from functools import reduce.
Євген Ярмаш

2
"1" як третій аргумент тут непотрібний, який випадок, коли це було б потрібно?
словаззаду

5
@wordsforthewise без третього аргументу він викидає виняток TypeError, якщо ви передасте йому порожню послідовність
Francisco Couzo

1
lambda x,y: x*yтакож працює замістьoperator.mul

78

Я б використав numpy.prodдля виконання завдання. Дивись нижче.

import numpy as np
mylist = [1, 2, 3, 4, 5, 6] 
result = np.prod(np.array(mylist))  

13
Зручно, якщо ви вже використовуєте Numpy. Вам, мабуть, навіть не потрібно спочатку ставити це як список, це повинно працювати в більшості випадківresult = np.prod(mylist)
Нік

4
Дві речі, на які слід звернути увагу: 1) Це може переповнитися, особливо якщо використовується типовий за замовчуванням numpy.int32вище. 2) Для невеликих списків це буде значно повільніше, оскільки NumPy потрібно виділити масив (актуально, якщо повторюється часто)
Закрито

1
переповнення для значень вище 21 тутnp.prod(np.array(range(1,21)))
PatrickT

Це не вдалий вибір. Він може переповнюватися і відбувається повільніше. спробуйте reduce.
Пейман

57

Якщо ви хочете уникнути що-небудь імпортувати і уникати більш складних областей Python, ви можете використовувати простий цикл

product = 1  # Don't use 0 here, otherwise, you'll get zero 
             # because anything times zero will be zero.
list = [1, 2, 3]
for x in list:
    product *= x

7
Незначна примітка: Фрагменти в Python дуже легкі, і оскільки ми тут маємо справу лише з примітивами, ви можете уникнути незначного хитру, починаючи з 1, починаючи зі списку [0] та повторюючи список [1:]. Хоча задоволення більш функціональними відповідями на "зменшення" тут є цінним у довгостроковій перспективі, оскільки це корисно і за інших обставин.
kungphu

@kungphu Порожній продукт, як правило, визначається як 1, ваше рішення замість нього викине виключення IndexError, якщо ви передасте йому порожню послідовність
Francisco Couzo

@Francisco Зрозуміло, але ця функція, мабуть, повинна викликати деякий аромат винятку в такому випадку, оскільки порожня послідовність буде недійсною для цієї функції. Насправді ця функція не має сенсу для будь-якої послідовності, що має менше двох значень; якщо ви передасте послідовність з одним значенням і помножите його на 1, ви по суті додали значення, якого там не було, і я б сказав, що це несподівана поведінка.
kungphu

1
@kungphu, поведінка для цієї відповіді правильна, тобто передача списку довжиною 1 повертає значення, а передання списку довжини 0 повертає 1. Це в тому ж режимі мислення, що дає суму ([]) як 0 або суму ([3]) як 3. Див: en.wikipedia.org/wiki/Empty_product
emorris

Я бачу ваш погляд на математичні функції. Однак у практичній ситуації розробки я б назвав це дуже рідкісною ситуацією, коли функція, яка явно призначена для роботи над входом, повинна повернути значення, яке враховує те, що не означає вхід або недійсний вхід. Я припускаю, що це залежить від мети вправи: Якщо це просто копіювати стандартну бібліотеку, гаразд, можливо, вона навчає людей чомусь про те, як (або) мова використовується чи може бути реалізована. В іншому випадку я б сказав, що це пропускає гарну можливість дати урок з дійсних та недійсних аргументів.
kungphu

14

Починаючи Python 3.8, .prodфункція була включена в mathмодуль у стандартній бібліотеці:

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

Метод повертає добуток startзначення (за замовчуванням: 1) разів ітерабельного чисел:

import math
math.prod([1, 2, 3, 4, 5, 6])

>>> 720

Якщо ітерабельний номер порожній, це призведе до отримання 1(або startзначення, якщо воно надане).


10

Ось кілька вимірювань продуктивності моєї машини. Доречно, якщо це виконується для невеликих входів у довго працюючу петлю:

import functools, operator, timeit
import numpy as np

def multiply_numpy(iterable):
    return np.prod(np.array(iterable))

def multiply_functools(iterable):
    return functools.reduce(operator.mul, iterable)

def multiply_manual(iterable):
    prod = 1
    for x in iterable:
        prod *= x

    return prod

sizesToTest = [5, 10, 100, 1000, 10000, 100000]

for size in sizesToTest:
    data = [1] * size

    timerNumpy = timeit.Timer(lambda: multiply_numpy(data))
    timerFunctools = timeit.Timer(lambda: multiply_functools(data))
    timerManual = timeit.Timer(lambda: multiply_manual(data))

    repeats = int(5e6 / size)
    resultNumpy = timerNumpy.timeit(repeats)
    resultFunctools = timerFunctools.timeit(repeats)
    resultManual = timerManual.timeit(repeats)
    print(f'Input size: {size:>7d} Repeats: {repeats:>8d}    Numpy: {resultNumpy:.3f}, Functools: {resultFunctools:.3f}, Manual: {resultManual:.3f}')

Результати:

Input size:       5 Repeats:  1000000    Numpy: 4.670, Functools: 0.586, Manual: 0.459
Input size:      10 Repeats:   500000    Numpy: 2.443, Functools: 0.401, Manual: 0.321
Input size:     100 Repeats:    50000    Numpy: 0.505, Functools: 0.220, Manual: 0.197
Input size:    1000 Repeats:     5000    Numpy: 0.303, Functools: 0.207, Manual: 0.185
Input size:   10000 Repeats:      500    Numpy: 0.265, Functools: 0.194, Manual: 0.187
Input size:  100000 Repeats:       50    Numpy: 0.266, Functools: 0.198, Manual: 0.185

Ви можете бачити, що Numpy є дещо повільнішим на менших входах, оскільки він виділяє масив перед тим, як проводиться множення. Також стежте за переповненням у Numpy.


Ви можете додати
евальський

Я підозрюю, що multiply_functoolsі multiply_numpy їх зважують, доводиться шукати np, functoolsі operatorглобалі, з подальшим пошуком атрибутів. Ви не проти перейти на місцевих жителів? _reduce=functools.reduce, _mul = operator.mul` у підписі функції, а потім return _reduce(_mul, iterable)у тілі тощо.
Martijn Pieters

1
Крім того, numpy версія повинна спочатку перетворити числа в numpy масив; зазвичай ви вже здійснили цю конверсію, щоб включити її в терміни не дуже справедливо. Коли список, перетворений в масивний масив один раз, np.prod()опція починається найшвидше на 100 елементів і більше.
Martijn Pieters

8

Мені особисто це подобається за функцію, яка множує всі елементи загального списку разом:

def multiply(n):
    total = 1
    for i in range(0, len(n)):
        total *= n[i]
    print total

Він компактний, використовує прості речі (змінну і for цикл), і мені здається інтуїтивно зрозумілим (схоже, як я б подумав про проблему, просто візьміть одну, помножте її, потім помножте на наступну тощо)! )


3
чудово, це найпростіший і найпростіший.
ghostkraviz

4
Чому немає for i in n:, то total *= i? чи не було б набагато простіше?
Мунім Мунна

@MunimMunnaIt не працював для мене вищезгаданим способом.
atul

5

Простий спосіб:

import numpy as np
np.exp(np.log(your_array).sum())

10
як щодо простоnp.prod(your_Array)
тире

3

Numpyмає prod()функцію, яка повертає добуток списку, або в цьому випадку, оскільки він нудний, це добуток масиву над заданою віссю:

import numpy
a = [1,2,3,4,5,6]
b = numpy.prod(a)

... інакше ви можете просто імпортувати numpy.prod():

from numpy import prod
a = [1,2,3,4,5,6]
b = prod(a)

2

Я знайшов це питання сьогодні, але я помітив, що у нього немає випадків, коли їх Noneу списку є. Отже, повним рішенням було б:

from functools import reduce

a = [None, 1, 2, 3, None, 4]
print(reduce(lambda x, y: (x if x else 1) * (y if y else 1), a))

У випадку додавання ми маємо:

print(reduce(lambda x, y: (x if x else 0) + (y if y else 0), a))

2
nums = str(tuple([1,2,3]))
mul_nums = nums.replace(',','*')
print(eval(mul_nums))

5
Будь ласка, додайте пояснення до своєї відповіді. Як відповісти
xenteros

3
Я призиваюсь і намагаюся пояснити код: особисто мені цей код не дуже подобається, оскільки він використовує eval, який інтерпретує рядок як аргумент або функцію (і, таким чином, зазвичай вважається небезпечною справою, особливо під час обробки вхідних даних ). Рядок перед цим замінює кожну розмежувальну кому мультипликативним *, таким, що eval визнає це мультипликативним. Цікаво, якою є ефективність щодо цього, особливо в порівнянні з іншими рішеннями
dennlinger

Ух, така погана ідея!
Ковальські

1

Я хотів би це наступним чином:

    def product_list(p):
          total =1 #critical step works for all list
          for i in p:
             total=total*i # this will ensure that each elements are multiplied by itself
          return total
   print product_list([2,3,4,2]) #should print 48

1

Це мій код:

def product_list(list_of_numbers):
    xxx = 1
    for x in list_of_numbers:
        xxx = xxx*x
    return xxx

print(product_list([1,2,3,4]))

результат: ('1 * 1 * 2 * 3 * 4', 24)


0

Як щодо використання рекурсії?

def multiply(lst):
    if len(lst) > 1:
        return multiply(lst[:-1])* lst[-1]
    else:
        return lst[0]


-1

'' 'єдиний простий метод для розуміння використання логіки для циклу' ''

Кол = [2,5,7,7,9] х = 1 для i в колі: x = i * x print (x)


Ваша відповідь не додає нічого нового для обговорення цього питання.
Сід

-3

Дуже просто нічого не імпортувати. Це мій код. Це визначить функцію, яка множить усі елементи у списку та повертає їх товар.

def myfunc(lst):
    multi=1
    for product in lst:
        multi*=product
    return product

2
Дублікат відповіді DeadChex, відповідь piSHOCK, відповідь Шакти Нандана. Не публікуйте відповідь, що вже пропонується.
Мунім Мунна

він також повинен повернути мульти | - |
Ларс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.