How to use Python reduce()

By

Learn how to use Python reduce() to calculate a single value from a list, like summing expenses, using a lambda and importing it from functools.

~~~

reduce() calculates a single value out of a sequence, like a list. You give it a function and a list, and it keeps combining items until only one value is left.

Python provides 3 useful global functions we can use to work with collections: map(), filter() and reduce().

Tip: sometimes list comprehensions make more sense and are generally considered more pythonic

Unlike the other two, reduce() is not available by default. You need to import it from the standard library module functools:

from functools import reduce

How does reduce() work?

The function you pass to reduce() takes 2 arguments: the accumulated value so far, and the next item in the list. Whatever the function returns becomes the accumulator for the next call.

Suppose you have a list of expenses, stored as tuples, and you want the total cost:

expenses = [
    ('Dinner', 80),
    ('Car repair', 120),
    ('Groceries', 45)
]

You could iterate with a loop over them:

total = 0
for expense in expenses:
    total += expense[1]

print(total) # 245

Or, you can use reduce() to reduce the list to a single value:

from functools import reduce

total = reduce(lambda acc, expense: acc + expense[1], expenses, 0)

print(total) # 245

The third argument, 0, is the initializer: the starting value of the accumulator. On the first call acc is 0 and expense is ('Dinner', 80). The lambda returns 80, which becomes acc for the next call, and so on.

Why the initializer matters

If you omit the initializer, reduce() uses the first item of the list as the starting accumulator. That’s fine when items and result have the same type, like summing plain numbers:

print(reduce(lambda a, b: a + b, [80, 120, 45])) # 245

With tuples it breaks. The first call receives two tuples, but from the second call on, a is a number and b is a tuple:

# TypeError: 'int' object is not subscriptable
reduce(lambda a, b: a[1] + b[1], expenses)

The fix is passing the initializer, so acc is a number from the start.

When should you reach for reduce()?

For a plain sum, sum() with a generator expression is shorter and clearer:

print(sum(expense[1] for expense in expenses)) # 245

reduce() earns its place when combining items is more than an addition. For example, finding the most expensive item:

most_expensive = reduce(lambda a, b: a if a[1] > b[1] else b, expenses)

print(most_expensive) # ('Car repair', 120)

Here no initializer is needed, because the accumulator and the items are both tuples.

Tagged: Python · All topics
~~~

Related posts about python: