## Introduction to Python’s reduce()

Python is a multi-paradigm programming language that supports a wide range of programming styles, including object-oriented, procedural, and functional programming. Functional programming is a programming paradigm that emphasizes the use of functions to create input data flow and avoid mutable data types.

One of the most useful functions in Python’s support for functional programming is the `reduce()`

function. In this article, we’ll explore the definition, history, and usage of Python’s `reduce()`

.

We’ll also discuss functional programming paradigms and Python’s support for it, and finally dive into examples of how `reduce()`

functions.

## Definition of reduce()

The `reduce()`

function is a built-in function in Python’s `functools`

module. It’s used to perform a folding or reduction of the elements in an iterable by applying a two-argument function cumulatively to the items in an iterable, starting from the first item.

In other words, the `reduce()`

function takes an iterable and applies a specified function pair-wise on the items of the iterable, reducing the sequence to a single value.

## Python’s support for functional programming

Python is known for its flexibility, and one of its crucial features is support for various programming styles. Python supports functional programming paradigms, which are based on pure functions, higher-order functions, recursion, and immutable data.

Python’s functional programming capabilities include lambda functions, recursion, iterators, generators, the `functools`

module, and the `itertools`

module. These features make it easy to write code that follows functional programming principles, and `reduce()`

is one of the most useful functions that enables the building of such programs.

## Historical background of Python’s reduce()

Guido van Rossum, the creator of Python, developed the first version of the `reduce()`

function in Python 2.x as an extension of the `map()`

and `filter()`

functions. The `reduce()`

function has also been used as a base function for other built-in functions such as `sum()`

, `min()`

, `max()`

, `any()`

, and `all()`

.

In Python 3.x, the `reduce()`

function was moved to the `functools`

module to separate it from the built-in functions to improve performance and readability.

## Getting Started with Python’s reduce()

The `reduce()`

function in Python is flexible and straightforward to use. It takes two arguments: a function that applies an operation to two arguments and an iterable that provides the sequence of values the operation is applied to.

The signature for the `reduce()`

function is as follows:

`reduce(function, iterable, initializer=None)`

The `function`

argument must be a binary operator, meaning that it takes two arguments. The `iterable`

argument must be an iterable type like a list, tuple, or string.

Here’s an example of how the `reduce()`

function works:

```
from functools import reduce
# Find the sum of all values in a list
list_sum = reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
print(list_sum)
```

In this example, the `reduce()`

function takes a lambda function that sums two numbers and an iterable (a list of integers). The function is applied pairwise on all elements of the iterable, and the function’s partial results are accumulated until obtaining the final result.

`reduce()`

in Python 2.x vs Python 3.x

In Python 2.x, the `reduce()`

function was a built-in function like the `map()`

and `filter()`

functions. To use the `reduce()`

function in Python 3.x, you need to import it from the `functools`

module.

The `functools`

implementation improves the `reduce()`

function’s performance and readability, but it means that you need to import the module before you can use the `reduce()`

function.

## Example of using a user-defined function with reduce()

Apart from using lambda functions, you can also use a user-defined function with the `reduce()`

function. Below is an example of how to do this:

```
from functools import reduce
def multiply(x, y):
"""Returns the result of multiplying two numbers"""
return x * y
# Find the product of all values in a list
lst = [1, 2, 3, 4, 5]
product = reduce(multiply, lst)
print(product)
```

In this example, we define a function called `multiply`

that takes two arguments and returns their product. We then pass the function and an iterable (a list of integers) to the `reduce()`

function.

The function is applied pairwise to the iterable, and the results are accumulated to obtain the final result.

## Conclusion

In this article, we’ve explored what the `reduce()`

function in Python is, its history, usage, and how it works with a user-defined function. We’ve also discussed functional programming paradigms and Python’s support for it.

Functional programming is particularly well-suited to data-centric and concurrent programming. The `reduce()`

function provides a straightforward way of applying a function iteratively to a sequence of values and obtaining the result.

Python’s support for functional programming opens up a new paradigm of programming in Python, making it easier to write more concise and readable code. If you haven’t already, it’s worth looking into functional programming in Python and exploring what you can achieve with the `reduce()`

function and other functional programming features.

### 3) The Optional Argument: Initializer

The `initializer`

argument is an optional third argument of the `reduce()`

function. It specifies a value or object that is used as the initial value for the reduction or partial computation.

If an initializer value is not provided, the first element of the iterable serves as the initial value. The `initializer`

argument is particularly useful when reducing an empty iterable, as it provides a default return value.

Without the `initializer`

value, attempting to reduce an empty iterable would result in a `TypeError`

. Here’s an example of how to use the `initializer`

argument with the `reduce()`

function:

```
from functools import reduce
# Reduce the following list of integers
lst = [1, 2, 3, 4, 5]
# Sum all elements of lst
result = reduce(lambda x, y: x + y, lst, 0) # we provide 0 as the initializer value
print(result) # 15
```

In this example, we use a lambda function to add two numbers, provide the iterable, and initialize the reduction value to 0. This code returns 15, the sum of all integers in the list.

If we don’t provide the initializer to this code:

`result = reduce(lambda x, y: x + y, [], 0)`

The code will return 0 since the iterable is empty, and while not providing an `initializer`

value would result in a `TypeError`

.

### 4) Reducing Iterables with Python’s reduce()

#### Summing Numeric Values

A common use case for the `reduce()`

function is the summation of numeric values within an iterable. Here’s an example of how `reduce()`

can be used to sum an iterable of numbers:

```
from functools import reduce
# Sum a list of integers using reduce() and a user-defined function
def sum_numbers(a, b):
return a + b
lst = [1, 2, 3, 4, 5]
total_sum = reduce(sum_numbers, lst)
print(total_sum) # 15
```

In this example, we define a user-defined function, `sum_numbers()`

, that takes two arguments, `a`

and `b`

, and adds them together. The `reduce()`

function applies this function to each item in the list, and the resulting sum is returned.

We could use a lambda function instead of a user-defined one in this case:

`total_sum = reduce(lambda x, y: x + y, lst)`

Since the add operator is a built-in function, we can also use it instead of a lambda function or user-defined function. This reduces the code to:

`total_sum = reduce(operator.add, lst)`

#### Introducing sum() built-in

While `reduce()`

is a useful function for reducing iterables with a custom function, it can be less readable compared to using the built-in function `sum()`

. `sum()`

is a Python built-in function that takes an iterable and returns the sum of the values.

```
# Sum the values in a Python list using the built-in sum() function
lst = [1, 2, 3, 4, 5]
total_sum = sum(lst)
print(total_sum) #15
```

In this example, we pass the list to the `sum()`

function and print the sum. The result of this code will be 15, which is the expected sum of all the integers in the list.

Using the `sum()`

built-in function is simpler and easier to read than using the `reduce()`

function. The built-in function takes an iterable as an argument and returns the sum of its values.

## Conclusion

In this article, we learned about the optional `initializer`

argument in Python’s `reduce()`

function. The `initializer`

argument is useful when reducing empty iterables and can provide a default return value when the iterable is empty.

We also explored reducing iterables with Python’s `reduce()`

function for a common use case, the summation of numeric values, and discussed the built-in function `sum()`

as an alternative to `reduce()`

when the operation is simply the sum of the iterable’s values.

### 5) Comparing reduce() and accumulate()

The `itertools`

module in Python provides another function, `accumulate()`

, which is similar to `reduce()`

but returns an iterable of the same length as the original input iterable instead of a single value. `accumulate()`

builds a sequence of partial results obtained by applying an operation to each item in the iterable.

By default, `accumulate()`

applies the addition operation to the iterable, but it can also accept a custom function. Here’s an example of using `accumulate()`

to sum an iterable:

```
import itertools
lst = [1, 2, 3, 4, 5]
cumulative_sum = list(itertools.accumulate(lst))
print(cumulative_sum) # [1, 3, 6, 10, 15]
```

In this example, we use the `accumulate()`

function to obtain the partial sum at each position of the list. A list of the accumulated sum is returned.

Let’s see an example of how to use `accumulate()`

to find the minimum and maximum values of an iterable:

```
import itertools
lst = [1, 2, 3, 4, 5]
min_values = list(itertools.accumulate(lst, min))
max_values = list(itertools.accumulate(lst, max))
print(min_values) # [1, 1, 1, 1, 1]
print(max_values) # [1, 2, 3, 4, 5]
```

We can see that the `min()`

function is gradually applied to each item in the iterable, and the previous minimum value is retained. Conversely, the `max()`

function is applied to each item in the iterable, and the previous maximum value is retained.

`Accumulate()`

Vs `Reduce()`

Examples:

`Accumulate()`

and `reduce()`

have similar functionality, but there are a few critical differences in how they behave. Below are examples that show how these differences manifest:

#### 1. Summing numeric values

```
import itertools
from functools import reduce
lst = [1, 2, 3, 4, 5]
reduce_sum = reduce(lambda x, y: x + y, lst)
accumulate_sum = list(itertools.accumulate(lst))
print(reduce_sum) # 15
print(accumulate_sum) # [1, 3, 6, 10, 15]
```

As we can see, `reduce()`

returns a single value, the sum of the iterable, while `accumulate()`

returns a list of the cumulative sums.

#### 2. Multiplying numeric values

```
import itertools
from functools import reduce
lst = [1, 2, 3, 4, 5]
reduce_prod = reduce(lambda x, y: x * y, lst)
accumulate_prod = list(itertools.accumulate(lst, lambda x, y: x * y))
print(reduce_prod) # 120
print(accumulate_prod) # [1, 2, 6, 24, 120]
```

In this example, we use lambda functions to multiply each item and return the cumulative product. The `reduce()`

function returns a single value, which is the product of all items in the list, while `accumulate()`

returns a list of the cumulative products.

#### 3. Finding minimum and maximum value

```
import itertools
from functools import reduce
lst = [1, 2, 3, 4, 5]
reduce_min = reduce(lambda x, y: x if x < y else y, lst)
accumulate_min = list(itertools.accumulate(lst, min))
reduce_max = reduce(lambda x, y: x if x > y else y, lst)
accumulate_max = list(itertools.accumulate(lst, max))
print(reduce_min) # 1
print(accumulate_min) # [1, 1, 1, 1, 1]
print(reduce_max) # 5
print(accumulate_max) # [1, 2, 3, 4, 5]
```

In this example, we get the minimum and maximum values of the list. The `reduce()`

function returns a single value, which is the minimum/maximum value in the list, while the `accumulate()`

function returns a list of the minimum/maximum values in the list at each position.

#### 4. Checking if all values are true

```
import itertools
from functools import reduce
lst_true = [True, True, True, True]
lst_false = [True, True, False, True]
reduce_true = reduce(lambda x, y: x and y, lst_true)
reduce_false = reduce(lambda x, y: x and y, lst_false)
accumulate_true = list(itertools.accumulate(lst_true, lambda x, y: x and y))
accumulate_false = list(itertools.accumulate(lst_false, lambda x, y: x and y))
print(reduce_true) # True
print(reduce_false) # False
print(accumulate_true) # [True, True, True, True]
print(accumulate_false) # [True, True, False, False]
```

In this example, we check if all the elements in the list are true. `reduce()`

returns a single Boolean value indicating whether all the items in the iterable are true or not.

In contrast, `accumulate()`

generates a sequence of the intermediate Boolean results.

#### 5. Checking if any value is true

```
import itertools
from functools import reduce
lst_true = [True, True, True, True]
lst_false = [False, False, False, False]
reduce_true = reduce(lambda x, y: x or y, lst_true)
reduce_false = reduce(lambda x, y: x or y, lst_false)
accumulate_true = list(itertools.accumulate(lst_true, lambda x, y: x or y))
accumulate_false = list(itertools.accumulate(lst_false, lambda x, y: x or y))
print(reduce_true) # True
print(reduce_false) # False
print(accumulate_true) # [True, True, True, True]
print(accumulate_false) # [False, False, False, False]
```

In this example, we check if any of the elements in the list are true. The `reduce()`

function reduces the iterable to a single Boolean value indicating whether any item in the iterable is true.

In contrast, `accumulate()`

generates a sequence of intermediate Boolean results.

### 6) Considering Performance and Readability

Performance is especially important in code that repeatedly performs the same operation. The logic behind this is that the faster the iteration, the quicker the code will execute.

Python is generally slower than other compiled programming languages, such as C, but it makes up for it through its readability and efficient syntax. Conversely, code readability is equally important since it determines how comfortable it is to read and understand the code.

Readable code is less prone to bugs and easier to maintain than code that is difficult to read. Python allows for a plethora of ways to solve folding problems.

One of the most common ones is using list comprehensions or generator expressions, which can be more memory-efficient and faster than other methods. Additionally,