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.

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

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+.


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

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

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


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.


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


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

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)

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

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

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

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)


0

Co powiesz na użycie rekurencji?

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


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


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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.