Reduce: The Swiss Army Knife of Basic Functional Programming
Gerry Wolfe
Posted on April 21, 2023
Functional programming is a paradigm that emphasizes the use of pure functions, immutable data, and higher-order abstractions. One of the most common and powerful higher-order abstractions in functional programming is the reduce function.
The reduce function takes an iterable (array, list, or other collection) and a function that combines two values, and applies that function to all the elements of the iterable returning a single value (which could be a primitive or an object). The canonical example is summing up an array of numbers.
# Python code
numbers = [1, 2, 3, 4, 5]
sum = reduce(lambda x, y: x + y, numbers)
assert (sum == 15) # True
// Typescript code
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((x, y) => x + y);
assert (sum === 15); // true
The power of the reduce function is its versatility. It can be used to implement many other iterable operations such as map, filter, find, etc.
For example, a filter function is just an implementation of reduce. Let’s see how we can use the reduce function to create our own filter function. A filter function takes an iterable and a predicate (a function that returns true or false), and returns a new object with only the elements that satisfy the predicate. To use the reduce function as a filter function, we need to define a filter function.
# Python code
def filter_by(acc, cur):
# Check if the current element satisfies the condition using the boolean function
if condition(cur):
# If True, append the current element to the accumulator array
acc.append(cur)
# Return the accumulator list
return acc
// Typescript code
function filterBy(acc: any[], cur: any): any[] {
// Check if the current element satisfies the condition using the boolean function
if (condition(cur)) {
// If true, push the current element to the accumulator array
acc.push(cur);
}
// Return the accumulator array
return acc;
}
Now we can use this function with the reduce function to filter out the even numbers from an array of numbers.
# Python code
numbers = [1, 2, 3, 4, 5]
# Define a boolean function that checks if a number is odd
def condition(x):
return x % 2 == 1
# Use reduce and filter_by to filter out the even numbers from numbers
odd_numbers = reduce(filter_by, numbers, [])
print(odd_numbers) # [1, 3, 5]
// Typescript code
const numbers = [1, 2, 3, 4, 5];
// Define a boolean function that checks if a number is odd
function condition(x: number): boolean {
return x % 2 == 1;
}
// Use reduce and filterBy to filter out the even numbers from numbers
const oddNumbers: number[] = numbers.reduce(filterBy, []);
console.log(oddNumbers); // [1,3,5]
Now, let's use reduce to return a Record object. If you have an array of strings that represent colors, you can use a reduce function to count how many times each color appears in the array and return an object with the color names as keys and the counts as values.
# Import reduce from functools module
from functools import reduce
# Define a list of colors
colors = ["red", "blue", "green", "red", "yellow", "blue", "green", "red"]
def get_color_counts(colors):
# Use reduce on the list
return reduce(lambda counts, color:
# For each color, check if it already exists as a key in the counts dictionary
counts.update({color: counts.get(color, 0) + 1}) or counts
# If yes, increment its value by one
# If no, initialize its value to one
# Use update and get methods on the dictionary and return the updated counts dictionary
, colors, {}) # Start with an empty dictionary for the counts
print(get_color_counts(colors)) # {'red': 3, 'blue': 2, 'green': 2, 'yellow': 1}
// Typescript code
const colors: string[] = ["red", "blue", "green", "red", "yellow", "blue", "green", "red"];
function getColorCounts(colors: string[]): Record<string, number> {
// Use the reduce method on the array
return colors.reduce((counts: Record<string, number>, color: string) => {
// For each color, check if it already exists as a key in the counts object
if (counts[color]) {
// If yes, increment its value by one
counts[color] += 1;
} else {
// If no, initialize its value to one
counts[color] = 1;
}
// Return the updated counts object
return counts;
}, {}); // Start with an empty object for the counts
}
console.log(getColorCounts(colors)); // {red: 3, blue: 2, green: 2, yellow: 1}
Those are just a few examples of the powerful functional nature of a reduce function that allows for concise and expressive transformations of iterable data structures. It can be used to implement many other higher-order functions such as map, filter, and find. The reduce function can help simplify complex computations and make code more elegant and efficient.
Posted on April 21, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.