Jak mogę pomnożyć wszystkie elementy na liście razem z Pythonem?

204

Muszę napisać funkcję, która pobiera listę liczb i mnoży je razem. Przykład: [1,2,3,4,5,6]da mi 1*2*3*4*5*6. Naprawdę mógłbym skorzystać z twojej pomocy.

użytkownik1897814
źródło

Odpowiedzi:

208

Python 3: użyj functools.reduce:

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

Python 2: użyj reduce:

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

Aby zachować zgodność z trybem 2 i 3, należy pip install six:

>>> from six.moves import reduce
>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
720
bogaty poziom
źródło
Nie importujesz operatora, więc to rozwiązanie jest nieco bardziej kompaktowe. Zastanawiam się, która jest szybsza.
odbył
30
@jheld: Zmierzyłem czas tworzenia liczb od 1 do 100. Zarówno w pythonie 2, jak i 3, lambdawziąłem średnio 0,02 s / 1000 powtórzeń, podczas operator.mulgdy średnio 0,009 s / 1000 powtórzeń, operator.mulprzyspieszając rząd wielkości.
whereswalden
4
@wordforthewise prawdopodobnie to przez to, że przejście przez dodatkową funkcję (lambda) dodaje napowietrznych, podczas gdy operator.mulidzie prosto do C.
whereswalden
4
Naprawdę nie nazwałbym 0,009 rzędem wielkości niższym niż 0,02. To tylko połowa.
jlh
1
Od wersji Python 3.8 można to po prostu zrobić math.prod([1,2,3,4,5,6]). (wymaga importu oczywiście)
Tomerikoo
168

Możesz użyć:

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

Zobacz wyjaśnienia reducei operator.muldokumentacje.

Potrzebujesz import functoolslinii w Pythonie 3+.

lody
źródło
32
Zauważ, że w python3 reduce()funkcja została usunięta z globalnej przestrzeni nazw i umieszczona w functoolsmodule. Więc w python3 musisz powiedzieć from functools import reduce.
Eugene Yarmash
2
„1” jako trzeci argument jest tutaj niepotrzebny, jaki jest przypadek, w którym byłby potrzebny?
wordsforthewise
5
@wordsforthewise bez trzeciego argumentu, zgłasza wyjątek TypeError, jeśli przekażesz mu pustą sekwencję
Francisco Couzo
1
lambda x,y: x*ydziała również zamiastoperator.mul
78

Użyłbym tego numpy.proddo wykonania zadania. Patrz poniżej.

import numpy as np
mylist = [1, 2, 3, 4, 5, 6] 
result = np.prod(np.array(mylist))  
belindanju
źródło
13
Wygodne, jeśli już korzystasz z Numpy. Prawdopodobnie nie musisz nawet najpierw przesyłać go jako listy, to powinno działać w większości przypadkówresult = np.prod(mylist)
Nick
4
Dwie rzeczy, na które należy uważać: 1) Może się przepełnić, szczególnie jeśli używasz domyślnej numpy.int32jak wyżej 2) W przypadku małych list będzie to znacznie wolniejsze, ponieważ NumPy musi przydzielić tablicę (istotne, jeśli często się powtarzają)
Disenchanted
1
przepełnienie dla wartości powyżej 21 tutajnp.prod(np.array(range(1,21)))
PatrickT
To nie jest dobry wybór. Może się przepełnić i jest wolniejszy. spróbuj reduce.
Peyman
57

Jeśli chcesz uniknąć importowania czegokolwiek i uniknąć bardziej złożonych obszarów Pythona, możesz użyć prostej pętli for

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
DeadChex
źródło
7
Drobna uwaga: Plasterki w Pythonie są bardzo łatwe, a ponieważ mamy tutaj do czynienia tylko z prymitywami, możesz uniknąć drobnych kłopotów, zaczynając od 1, zaczynając od listy [0] i iterując po liście [1:]. Chociaż wygoda z bardziej funkcjonalnymi odpowiedziami „zmniejszającymi” jest tutaj cenna w dłuższej perspektywie, ponieważ jest również przydatna w innych okolicznościach.
kungphu
@ kungphu Pusty produkt jest zwykle definiowany jako 1, twoje rozwiązanie rzuciłoby wyjątek IndexError, jeśli podasz mu pustą sekwencję
Francisco Couzo
@Francisco Przyznaję, ale ta funkcja prawdopodobnie powinna w tym przypadku wywołać pewien wyjątek, ponieważ pusta sekwencja byłaby niepoprawna dla tej funkcji. W rzeczywistości funkcja ta nie ma znaczenia dla żadnej sekwencji o mniej niż dwóch wartościach; jeśli przejdziesz sekwencję z jedną wartością i pomnożysz ją przez 1, zasadniczo dodałeś wartość, której tam nie było, co, jak powiedziałbym, sprowadza się do nieoczekiwanego zachowania.
kungphu,
1
@ kungphu zachowanie dla tej odpowiedzi jest poprawne, tzn. przekazanie listy o długości 1 zwraca wartość, a przekazanie listy o długości 0 zwraca 1. Jest w tym samym myśleniu, co daje sumę ([]) jako 0 lub sumę ([3]) jako 3. Patrz: en.wikipedia.org/wiki/Empty_product
emorris
Widzę twój punkt widzenia na funkcje matematyczne. Jednak w praktycznej sytuacji programistycznej nazwałbym to bardzo rzadką sytuacją, w której funkcja, która jest wyraźnie przeznaczona do działania na danych wejściowych, powinna zwrócić wartość, biorąc pod uwagę, co oznacza brak danych wejściowych lub nieprawidłowe dane wejściowe. Przypuszczam, że zależy to od celu ćwiczenia: jeśli chodzi tylko o odtworzenie standardowej biblioteki, OK, być może uczy ludzi czegoś o tym, jak (lub a) język jest lub może być zaimplementowany. W przeciwnym razie powiedziałbym, że traci dobrą okazję, aby udzielić lekcji na temat prawidłowych i nieprawidłowych argumentów.
kungphu
14

Zaczynając Python 3.8, .prodfunkcja została dołączona do mathmodułu w standardowej bibliotece:

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

Metoda zwraca iloczyn startwartości (domyślnie: 1) razy iterowalnej liczby:

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

>>> 720

Jeśli iterowalny jest pusty, wygeneruje 1(lub startwartość, jeśli podano).

Xavier Guihot
źródło
10

Oto kilka pomiarów wydajności z mojej maszyny. Istotne w przypadku, gdy jest to wykonywane dla małych wejść w długo działającej pętli:

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}')

Wyniki:

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

Widać, że Numpy jest nieco wolniejszy na mniejszych wejściach, ponieważ przydziela tablicę przed wykonaniem mnożenia. Uważaj też na przepełnienie Numpy.

Niezadowolony
źródło
Możesz dodać ewaluację z ciekawości
Mr_and_Mrs_D
Podejrzewam, że multiply_functoolsi multiply_numpy są przygnieciony konieczności patrzenia w górę np, functoolsi operatorglobalnych, a następnie przez wyszukiwań atrybutów. Czy miałbyś coś przeciwko przestawieniu się na mieszkańców? _reduce=functools.reduce, _mul = operator.mul` w sygnaturze funkcji, a następnie return _reduce(_mul, iterable)w treści itd.
Martijn Pieters
1
Ponadto wersja numpy musi najpierw przekonwertować liczby na tablicę numpy; normalnie dokonałeś już tej konwersji, więc uwzględnienie jej w harmonogramach nie jest tak naprawdę uczciwe. Po jednokrotnym przekonwertowaniu listy na tablicę numpy np.prod()opcja zaczyna się najszybciej przy 100 lub więcej elementach.
Martijn Pieters
8

Osobiście podoba mi się ta funkcja, która zwielokrotnia wszystkie elementy listy ogólnej:

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

Jest kompaktowy, wykorzystuje proste rzeczy (zmienną i pętlę for) i jest dla mnie intuicyjny (wygląda na to, jak bym pomyślał o problemie, wystarczy wziąć jeden, pomnożyć go, a następnie pomnożyć przez następny i tak dalej! )

użytkownik5038135
źródło
3
świetnie, to jest najprostsze i najbardziej proste.
ghostkraviz
4
Dlaczego nie for i in n:, wtedy total *= i? czy nie byłoby to o wiele prostsze?
Munim Munna
@MunimMunnaNie działało to dla mnie w powyższy sposób.
athul
5

Prosty sposób to:

import numpy as np
np.exp(np.log(your_array).sum())
XXinyue
źródło
10
a może po prostunp.prod(your_Array)
dashy
3

Numpyma prod()funkcję, która zwraca iloczyn listy, lub w tym przypadku, ponieważ jest numpy, jest iloczynem tablicy nad daną osią:

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

... lub możesz po prostu zaimportować numpy.prod():

from numpy import prod
a = [1,2,3,4,5,6]
b = prod(a)
Leo Igane
źródło
2

Znalazłem to pytanie dzisiaj, ale zauważyłem, że nie ma przypadku, w którym są Nonena liście. Tak więc kompletnym rozwiązaniem byłoby:

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

W przypadku dodania mamy:

print(reduce(lambda x, y: (x if x else 0) + (y if y else 0), a))
Xxxo
źródło
2
nums = str(tuple([1,2,3]))
mul_nums = nums.replace(',','*')
print(eval(mul_nums))
M. Dickson
źródło
5
Dodaj wyjaśnienie do swojej odpowiedzi. Jak odpowiedzieć
Xenteros
3
Wchodzę i próbuję wyjaśnić kod: osobiście nie podoba mi się ten kod, ponieważ używa eval, który interpretuje ciąg jako argument lub funkcję (i dlatego jest ogólnie postrzegany jako niebezpieczna rzecz do zrobienia, szczególnie podczas obsługi danych wejściowych ). Poprzednia linia zastępuje każdy przecinek rozdzielający multiplikatywem *, tak że eval rozpozna to jako multiplikatyw. Zastanawiam się, jak na tym wygląda wydajność, szczególnie w porównaniu z innymi rozwiązaniami
dennlinger,
Wow, taki zły pomysł!
Kowalski
1

Chciałbym to w następujący sposób:

    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
Shakti Nandan
źródło
1

To jest mój kod:

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]))

wynik: („1 * 1 * 2 * 3 * 4”, 24)

jackim
źródło
0

Co powiesz na użycie rekurencji?

def multiply(lst):
    if len(lst) > 1:
        return multiply(lst[:-1])* lst[-1]
    else:
        return lst[0]
mtdkki
źródło
-1

Moje rozwiązanie:

def multiply(numbers):
    a = 1
    for num in numbers:
        a *= num
        return a

  pass
Dorian Vanzant
źródło
-1

'' jedyna prosta metoda zrozumienia logiki użycia pętli ''

Lap = [2,5,7,7,9] x = 1 dla i na Lap: x = i * x print (x)

Sandeep Raturi
źródło
Twoja odpowiedź nie dodaje nic nowego do dyskusji na temat tego pytania.
Sid
-3

To bardzo proste, nic nie importuj. To jest mój kod. Spowoduje to zdefiniowanie funkcji, która zwielokrotnia wszystkie pozycje na liście i zwraca ich produkt.

def myfunc(lst):
    multi=1
    for product in lst:
        multi*=product
    return product
Aditya
źródło
2
Duplikat odpowiedzi DeadChex, odpowiedzi piSHOCK, odpowiedzi Shakti Nandan. Nie publikuj odpowiedzi, które są już sugerowane.
Munim Munna
powinien również zwrócić multi | - |
Lars