How can I multiply all items in a list together with Python?
Asked Answered
P

15

284

Given a list of numbers like [1,2,3,4,5,6], how can I write code to multiply them all together, i.e. compute 1*2*3*4*5*6?

Premiere answered 12/12, 2012 at 13:0 Comment(0)
R
260

Python 3: use functools.reduce:

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

Python 2: use reduce:

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

For compatible with 2 and 3 use Six (pip install six), then:

>>> from six.moves import reduce
>>> reduce(lambda x, y: x*y, [1,2,3,4,5,6])
720
Runnels answered 12/12, 2012 at 13:3 Comment(7)
You don't import operator, so this solution is a bit more compact. I wonder which is faster.Nob
@jheld: I timed product-ing the numbers from 1 to 100. In both python2 and 3, lambda took an average of .02s/1000 repetitions, whereas operator.mul took an average of .009s/1000 repetitions, making operator.mul an order of magnitude faster.Horeb
@Horeb Any idea as to why?Geanticline
@Geanticline probably it's that going through an extra function (lambda) adds overhead, whereas operator.mul goes straight to C.Horeb
I really wouldn't call .009 an order of magnitude lower than .02. It's just about half.Ari
As of Python 3.8, it can be simply done with math.prod([1,2,3,4,5,6]). (requires import of-course)Langbehn
You don't need to install six to use the same syntax in Python 2.6 or 2.7 as in Python 3. You just need to use the same line from functools import reduce as used in Python 3.Mckean
A
197

You can use:

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

See reduce and operator.mul documentations for an explanation.

You need the import functools line in Python 3+.

Akan answered 12/12, 2012 at 13:3 Comment(3)
Note that in python3, the reduce() function has been removed from the global namespace and placed in the functools module. So in python3 you need to say from functools import reduce.Clobber
The '1' as the third argument is unnecessary here, what's a case where it would be needed?Geanticline
@Geanticline without the third argument, it throws a TypeError exception if you pass it an empty sequenceProbable
R
123

I would use the numpy.prod to perform the task:

import numpy as np

mylist = [1, 2, 3, 4, 5, 6] 
result = np.prod(np.array(mylist))  
Rainer answered 6/9, 2015 at 17:54 Comment(4)
Convenient if you're already using Numpy. You probably don't even need to cast it as a list first, this should work for most cases result = np.prod(mylist)Shelburne
Two things to watch out for: 1) It might overflow, especially if using the default numpy.int32 as above 2) For small lists this will be significantly slower, since NumPy needs to allocate an array (relevant if repeated often)Extricate
overflow for values above 21 here np.prod(np.array(range(1,21)))Jarboe
It is not a good choice. It can overflow and it is slower. try reduce.Rosina
D
80

If you want to avoid importing anything and avoid more complex areas of Python, you can use a simple for loop:

nums = [1, 2, 3]

product = 1  # Don't use 0 here, otherwise, you'll get zero 
             # because anything times zero will be zero.
for num in nums:
    product *= num
Dilate answered 12/12, 2012 at 15:47 Comment(5)
Minor note: Slices in Python are very easy, and since we're only dealing with primitives here, you can avoid the minor kludge of starting with 1 by starting with list[0] and iterating over list[1:]. Though getting comfortable with the more functional 'reduce' answers here is valuable in the long term as it's also useful in other circumstances.Almanza
@Almanza The empty product is usually defined as 1, your solution would throw an IndexError exception instead if you pass it an empty sequenceProbable
@Probable Granted, but this function probably should throw some flavor of exception in that case, since an empty sequence would be invalid input for this function. In fact, this function is not meaningful for any sequence with less than two values; if you pass a sequence with one value and multiply it by 1, you've essentially added a value that wasn't there, which I'd say amounts to unexpected behavior.Almanza
@kungphu, the behaviour for this answer is correct, i.e. passing a list of length 1 returns the value, and passing a list of length 0 returns 1. It's in the same line of thinking that gives sum([]) as 0 or sum([3]) as 3. See: en.wikipedia.org/wiki/Empty_productUnbated
I see your point regarding mathematical functions. However, in a practical development situation, I would call it a very rare situation where a function that's explicitly intended to operate on input should return a value given what amounts to no input or invalid input. I suppose it depends on the goal of the exercise: If it's just to replicate the standard library, OK, perhaps it teaches people something about how the (or a) language is or can be implemented. Otherwise I'd say it misses out on a good opportunity to provide a lesson on valid and invalid arguments.Almanza
R
75

In Python 3.8 and up, the math standard library module provides .prod for this purpose:

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

The method returns the product of a start value (default: 1) times an iterable of numbers:

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

If the iterable is empty, this will produce 1 (or the start value, if provided).

Revision answered 14/2, 2019 at 19:32 Comment(0)
E
16

Here's some performance measurements from my machine. Relevant in case this is performed for small inputs in a long-running loop:

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

Results:

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

You can see that Numpy is quite a bit slower on smaller inputs, since it allocates an array before multiplication is performed. Also, watch out for the overflow in Numpy.

Extricate answered 28/11, 2017 at 12:44 Comment(3)
You could add the eval way just out of curiosityKoziol
I suspect that multiply_functools and multiply_numpy are weighed down by having to look up the np,functools and operator globals, followed by attribute lookups. Would you mind switching to locals? _reduce=functools.reduce, _mul=operator.mul` in the function signature then return _reduce(_mul, iterable) in the body, etc.Norway
Also, the numpy version has to first convert the numbers to a numpy array; you'd normally already have made that conversion, to include that in the timings is not really fair. With the list converted to a numpy array once, the np.prod() option starts becomes fastest at 100 elements or more.Norway
L
8

Numpy has the prod() function that returns the product of a list, or in this case since it's numpy, it's the product of an array over a given axis:

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

...or else you can just import numpy.prod():

from numpy import prod
a = [1,2,3,4,5,6]
b = prod(a)
Learnt answered 21/8, 2019 at 5:5 Comment(0)
M
7

I personally like this for a function that multiplies all elements of a generic list together:

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

It's compact, uses simple things (a variable and a for loop), and feels intuitive to me (it looks like how I'd think of the problem, just take one, multiply it, then multiply by the next, and so on!)

Modica answered 22/6, 2015 at 23:31 Comment(1)
Why not for i in n:, then total *= i? would not it be much simpler?Afflict
A
5

The simple way is:

import numpy as np
np.exp(np.log(your_array).sum())
Andrew answered 13/1, 2018 at 20:55 Comment(2)
what about just np.prod(your_Array)Hoskins
a) taking logs is expensive. b) ill behaved for for zero and negative values.. could be fixed by using abs, and counting the negatives, and bailing if there is a zero either by checking in advance or by the exception. regardless, it's expensiveAugean
A
3
nums = str(tuple([1,2,3]))
mul_nums = nums.replace(',','*')
print(eval(mul_nums))
Acorn answered 9/9, 2016 at 5:26 Comment(4)
Please add some explanation to your answer. How to AnswerBalance
I chime in and try to explain the code: I personally like this code not much, since it uses eval, which interpretes the string as an argument or function (and is thus generally viewed as an unsafe thing to do, especially when handling input data). The line before that replaces every delimiting comma by a multiplicative *, such that eval will recognize this as a multiplicative. I wonder how the performance on this is, espcially in comparison to other solutionsNormally
Wow, such a bad idea!Fillin
Do not ever use eval (or exec) on data that could possibly come from outside the program in any form. It is a critical security risk. You allow the author of the data to run arbitrary code on your computer. It cannot easily be sandboxed, and proper sandboxing is harder than using a proper tool for the job.Calley
M
3

Just wanna add a Python 3.8 One-liner answer:

def multiply(l):
    return [b := 1, [b := b * a for a in l]][-1][-1]


print(multiply([2, 3, 8, 10]))

output:

480

explanation:

  • [b := 1, is for defining a temporary variable

  • ...[b := b * a for a in l] is for iterating over the list and multiplying b by every element

  • ...[-1][-1] is because the final list is [b, [b * l[0], b * l[1], ..., b * l[-1]]]. and so the element in the final position is the multiplication of all of the elements in the list.

Mysia answered 24/7, 2022 at 11:28 Comment(2)
The := operator was added in 3.8, and this works in 3.8 and up. However, this is needlessly cryptic.Calley
Thanks for the comment, however, my solution isn't aiming to be efficient or pretty, the only reason for it is being a one-liner.Mysia
B
2

Found this question today but I noticed that it does not have the case where there are None's in the list. So, the complete solution would be:

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

In the case of addition, we have:

print(reduce(lambda x, y: (x if x else 0) + (y if y else 0), a))
Bejewel answered 7/7, 2016 at 14:58 Comment(0)
B
0

How about using recursion?

def multiply(lst):
    if len(lst) > 1:
        return multiply(lst[:-1])* lst[-1]
    else:
        return lst[0]
Barnaul answered 5/3, 2018 at 8:39 Comment(0)
D
0

One way you can use is math.prod() For example:

import math
arr = [1, 2, 3, 4]
print(math.prod(arr))

Another way is numpy.prod() This is another library to import

import numpy
arr = [1, 2, 3, 4]
print(numpy.prod(arr))
Dipper answered 5/2, 2023 at 0:4 Comment(0)
L
-1

There are many good answers in this thread. If you want to do multiply a list in actual production I recommend using standard numpy or math packages.

If you are just looking for a quick and dirty solution and you don’t want to import anything you can do this:

l = [1,2,3,4,5,6]

def list_multiply(l):
    return eval('*'.join(map(str,l)))
    
print(list_multiply(l))
#Output: 720

map(str,l) converts each element in the list to a string. join combines each element into one string separated by the * symbol. eval converts the string back into a function that can evaluated.

Warning: eval is considered dangerous to use, especially if the program accepts user input because a user can potentially inject any function into the code and compromise your system.

Limann answered 26/11, 2022 at 17:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.