What's the function like sum() but for multiplication? product()? [duplicate]
Asked Answered
E

9

266

Python's sum() function returns the sum of numbers in an iterable.

sum([3,4,5]) == 3 + 4 + 5 == 12

I'm looking for the function that returns the product instead.

somelib.somefunc([3,4,5]) == 3 * 4 * 5 == 60

I'm pretty sure such a function exists, but I can't find it.

Epeirogeny answered 27/2, 2009 at 16:6 Comment(0)
A
151

Update:

In Python 3.8, the prod function was added to the math module. See: math.prod().

Older info: Python 3.7 and prior

The function you're looking for would be called prod() or product() but Python doesn't have that function. So, you need to write your own (which is easy).

Pronouncement on prod()

Yes, that's right. Guido rejected the idea for a built-in prod() function because he thought it was rarely needed.

Alternative with reduce()

As you suggested, it is not hard to make your own using reduce() and operator.mul():

from functools import reduce  # Required in Python 3
import operator
def prod(iterable):
    return reduce(operator.mul, iterable, 1)

>>> prod(range(1, 5))
24

Note, in Python 3, the reduce() function was moved to the functools module.

Specific case: Factorials

As a side note, the primary motivating use case for prod() is to compute factorials. We already have support for that in the math module:

>>> import math

>>> math.factorial(10)
3628800

Alternative with logarithms

If your data consists of floats, you can compute a product using sum() with exponents and logarithms:

>>> from math import log, exp

>>> data = [1.2, 1.5, 2.5, 0.9, 14.2, 3.8]
>>> exp(sum(map(log, data)))
218.53799999999993

>>> 1.2 * 1.5 * 2.5 * 0.9 * 14.2 * 3.8
218.53799999999998

Note, the use of log() requires that all the inputs are positive.

Alpers answered 6/2, 2018 at 17:32 Comment(1)
You might want to add that the floats in the last example need to be positive. Otherwise, you might have to use cmath, but even then it won't really work in all cases.Inflexion
C
239

Historically, Guido vetoed the idea: http://bugs.python.org/issue1093

As noted in that issue, you can make your own:

from functools import reduce # Valid in Python 2.6+, required in Python 3
import operator

reduce(operator.mul, (3, 4, 5), 1)
Canoness answered 27/2, 2009 at 16:13 Comment(10)
Here is a great example of where there is a "need for this," to quote Guido: product(filter(None, [1,2,3,None])). Hopefully it will be included someday.Supererogation
Isn't Guido also the guy who doesn't like reduce?Archdiocese
Yep -- and reduce is no longer even a builtin in Python 3. IMO, we don't need every possible list operator added to the global builtins when a standard (or 3rd party) library would do. The more builtins you have, the more common words become off-limits as local variable names.Canoness
Just found this nugget in Guido's blog post about reduce(). "We already have sum(); I'd happily trade reduce() for product()...". If anyone wants to petition for including product() in the standard library, the number of views on this question may help make the case.Epeirogeny
@PatrickMcElhaney It sounds like python3 already got rid of the reduce builtin. I think product missed its chance. ;)Canoness
@Supererogation I don't get it, what's wrong with import operator; print(reduce(operator.mul,filter(None, [1,2,3,None])))?Baba
@Baba [0, 1, 2, 3] now results in 6 instead of 0Accra
So how come sum() got a free pass then?Roosevelt
I wish he would've explained his "dissuasion".Ereshkigal
An obvious case of not foreseeing things like Sagemath and the routine need to compute products (as well as sums) of thousands of elements in various algebras in which this is entirely feasible and does not cause the representation to explode.Subroutine
A
151

Update:

In Python 3.8, the prod function was added to the math module. See: math.prod().

Older info: Python 3.7 and prior

The function you're looking for would be called prod() or product() but Python doesn't have that function. So, you need to write your own (which is easy).

Pronouncement on prod()

Yes, that's right. Guido rejected the idea for a built-in prod() function because he thought it was rarely needed.

Alternative with reduce()

As you suggested, it is not hard to make your own using reduce() and operator.mul():

from functools import reduce  # Required in Python 3
import operator
def prod(iterable):
    return reduce(operator.mul, iterable, 1)

>>> prod(range(1, 5))
24

Note, in Python 3, the reduce() function was moved to the functools module.

Specific case: Factorials

As a side note, the primary motivating use case for prod() is to compute factorials. We already have support for that in the math module:

>>> import math

>>> math.factorial(10)
3628800

Alternative with logarithms

If your data consists of floats, you can compute a product using sum() with exponents and logarithms:

>>> from math import log, exp

>>> data = [1.2, 1.5, 2.5, 0.9, 14.2, 3.8]
>>> exp(sum(map(log, data)))
218.53799999999993

>>> 1.2 * 1.5 * 2.5 * 0.9 * 14.2 * 3.8
218.53799999999998

Note, the use of log() requires that all the inputs are positive.

Alpers answered 6/2, 2018 at 17:32 Comment(1)
You might want to add that the floats in the last example need to be positive. Otherwise, you might have to use cmath, but even then it won't really work in all cases.Inflexion
F
49

There's a prod() in numpy that does what you're asking for.

Frequently answered 15/6, 2011 at 21:33 Comment(4)
note: doesn't support Python longs (arbitrary precision integers) so np.prod(range(1,13)) gives the correct answer equal to 12! but np.prod(range(1,14)) does not.Inclinable
@JasonS np.prod(arange(1,14, dtype='object'))?Keverne
The math.prod() function will make this answer obsolete.Toolmaker
Still tedious to have to import math when you want to do this in a simple one-liner. I miss reduce() and the Guido-rejected product().Roosevelt
M
43

There isn't one built in, but it's simple to roll your own, as demonstrated here:

import operator
def prod(factors):
    return reduce(operator.mul, factors, 1)

See answers to this question:

Which Python module is suitable for data manipulation in a list?

Mccowyn answered 27/2, 2009 at 16:11 Comment(8)
If using Python 3 use functools.reduce instead of reduce.Warmongering
For even more functools fun: prod = functools.partial(functools.reduce, operator.mul)Sporogonium
So in Python 3 I need two imports to do something so basic?!Undoing
@A.Donda You need to use imports in Python to do far more basic things: the square root function is in Math, Threads are in threading, etc etc. Python doesn't eschew namespaces, it's actually an explicit part of the Zen of Python that it embraces them.Carbuncle
@MarcelBesixdouze, yes, I agree that namespaces are one honking great idea. But imho in a language that has native lists, multiplying a bunch of numbers should be a builtin. And I consider it to be more basic than square roots and threading. In particular the latter is complex enough to warrant a module.Undoing
@A.Donda Python's "list" is a dynamic array, not a list. But given that python lists and iterators are so important, I would expect 'product' to do a cartesian product of iterables, if anything. Other languages where it's easy to do this usually just have variadic "add" and "times" functions that take any number of arguments, rather than actually operating on lists.Carbuncle
@MarcelBesixdouze, yes, just like 'sum' does a cartesian sum of iterables.Undoing
@A.Donda I'm not aware of that. sum calls +, and there is no + defined for general iterators. If there were, it should be chaining (itertools.chain), just like if * were defined on iterators it should do product (itertools.product).Carbuncle
W
29
Numeric.product 

( or

reduce(lambda x,y:x*y,[3,4,5])

)

Waxplant answered 27/2, 2009 at 16:9 Comment(6)
He wants a function he can load from a module or library, not writing the function himself.Neckline
But if there isn't one, he probably still wants the function.Broker
Right, but he needs to know one doesn't exist, since that's his main question.Neckline
You also have to give reduce a default value of 1 otherwise it will fail in the null case. The product of an empty sequence is defined as 1.Skimpy
@CraigMcQueen Numeric is (one of) the predecessors of numpy.Serigraph
An example of how to use Numeric.product, and how to import it, would make this answer even better!Rozier
C
24

Use this

def prod(iterable):
    p = 1
    for n in iterable:
        p *= n
    return p

Since there's no built-in prod function.

Carnal answered 27/2, 2009 at 16:10 Comment(6)
you must think reduce really is an antipattern :)Mccowyn
He wanted to know if an existing function exists that he can use.Neckline
And this answer explainss that there isn't one.Rheostat
@zweiterlinde: For beginners, reduce leads to problems. In this case, using lambda a,b: a*b, it isn't a problem. But reduce doesn't generalize well, and gets abused. I prefer beginners not learn it.Carnal
@Carnal I've never seen any beginners use reduce, much less any other functional-esque constructs. Heck, even "intermediate" programmers usually don't know much beyond a list comprehension.Truculent
FWIW this is about 25~30% faster than the reduce-based solutionKirstinkirstyn
C
8

Perhaps not a "builtin", but I consider it builtin. anyways just use numpy

import numpy 
prod_sum = numpy.prod(some_list)
Centralia answered 10/2, 2019 at 23:17 Comment(1)
That's dangerously close to a "works on my machine" statement! Numpy, lovely though it is, is unequivocaly not a builtin.Roosevelt
L
4

I prefer the answers a and b above using functools.reduce() and the answer using numpy.prod(), but here is yet another solution using itertools.accumulate():

import itertools
import operator
prod = list(itertools.accumulate((3, 4, 5), operator.mul))[-1]
Lecturer answered 30/11, 2017 at 18:55 Comment(0)
L
1

You can also encode your list of numbers as a pd.Series and then use pd.Series.product():

>>> import pandas as pd
>>> pd.Series([5,3,-1]).product()
-15
Lazos answered 11/9, 2022 at 11:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.