In what cases is it useful and how can I use the reduce
function?
In what cases is it useful and how can I use the reduce
function?
The reduce
function, available in the built-in module functools
, serves to "reduce" an iterable (as a list) to a single value.
It is a somewhat more common paradigm in functional languages, but it is also very useful in imperative / object-oriented languages such as Python.
But how do you "reduce" a list?
Suppose you have a minha_lista
list, which only contains numbers, and that you want the multiplication result among all those numbers. One of the ways to do this is with a for:
# Queremos 2 * 4 * 5 * 2, que é igual a 80
minha_lista = [2, 4, 5, 2]
produto_total = 1
for numero in minha_lista:
produto_total *= numero
print(produto_total) # 80
This works, but it can also be done with reduce
:
from functools import reduce
minha_lista = [2, 4, 5, 2]
def mult(x, y):
return x * y
produto_total = reduce(mult, minha_lista)
print(produto_total) # 80
Or, equivalently but a bit more concise, with a lambda function (which is nothing more than a function defined in a single expression / line):
from functools import reduce
minha_lista = [2, 4, 5, 2]
produto_total = reduce(lambda x, y: x * y, minha_lista)
print(produto_total) # 80
So what's going on there? If we take a look at "slow motion", what happens is this:
reduce
receives as function argument applied the function mult
(or lambda, in the second case) reduce
receives as iterable the minha_lista
reduce
considers as x
and y
, respectively, the first two elements of minha_lista
: 2 and 4 reduce
applies to x
and y
the mult
function, which multiplies one by the other: in 2 * 4
, the result is 8. x
, and the next element unprocessed (5, third element of our list) becomes y
mult
function is applied to x
and y
: 8 * 5
returns 40
, and this returned value becomes our new x
The mult
function is last applied to x
and the last element in our list, 2
. 40 * 2
returns us 80
Since there are no more elements to apply the function, reduce
returns the final result: 80, as expected.
In short, the function applies another function sequentially and cumulatively to a list (iterator), and "reduces" the list to a single final result.
Another didactic example is to calculate the minimum value of a list:
from functools import reduce
minha_lista = [2, 4, 5, 2, 1]
def achar_minimo(x, y):
if x < y:
return x
else:
return y
minimo = reduce(achar_minimo, minha_lista)
print(minimo) # 1
In this case, the first argument x
is used to store the smallest value seen, and it is compared to the other y
values in the list.
I say this example is didactic because there is already an equivalent function in Python: the min
. Still, I think the example is cool to give another idea of the power of reduce
.
In addition to the above, reduce
also accepts an optional third argument, initial_value
. As the name implies, this argument can be given as the initial value, and is in effect the same thing as putting this value at the beginning of your list.
These examples are simple and may seem silly, but as the functions applied become more complex, using reduce
may be a good way to decrease the size of the code and make it clearer. Either way, it's a good tool to have.