Write more semantic code with functional programming
Do you ever look at your code and see a waterfall of for loops? Do you find yourself having to squint your eyes and lean towards your monitor to get a closer look?
I know I do.
For loops are a Swiss army knife for problem-solving, but, when it comes to scanning code to get a quick read of what you’ve done, they can be overwhelming.
What are Map, Filter, and Reduce?
Reviewing my previously written code, I realized that 95% of the time when looping through strings or arrays I do one of the following: map a sequence of statements to each value, filter values that meet specific criteria, or reduce the data set to a single aggregate value.
With that insight, these three methods are recognition — and implementation — that the reason you loop through an iterable often falls into one of these three functional categories:
- Map: Apply the same set of steps to each item, storing the result.
- Filter: Apply validation criteria, storing items that evaluate True.
- Reduce: Return a value that is passed from element to element.
What Makes Python Map/Filter/Reduce Different?
In Python, the three techniques exist as functions, rather than methods of the Array or String class. This means that instead of writing
my_array.map(function) you would write
The syntax between a lambda expression and arrow function is actually quite similar. Swap the
=> for a
: and make sure to use the keyword
lambda and the rest is almost identical.
One key difference between arrow functions and lambda expressions is that arrow functions are able to expand into full-blown functions with multiple statements while lambda expressions are limited to a single expression that is returned. Thus, when using
reduce() if you need to perform multiple operations on each item, define your function first then include it.
def inefficientSquare(number): result = number * number return resultmap(inefficientSquare, my_list)
Replacing For Loops
All right, on to the good stuff. Here are three examples of common for loops that will be replaced by map, filter, and reduce. Our programming prompt: Calculate the sum of the squared odd numbers in a list.
First, the example with basic for loops. Note: This is purely for demonstration and could be improved even without map/filter/reduce.
numbers = [1,2,3,4,5,6] odd_numbers =  squared_odd_numbers =  total = 0# filter for odd numbers for number in numbers: if number % 2 == 1: odd_numbers.append(number)# square all odd numbers for number in odd_numbers: squared_odd_numbers.append(number * number)# calculate total for number in squared_odd_numbers: total += number# calculate average
Let’s convert each step to one of the functions:
from functools import reducenumbers = [1,2,3,4,5,6]odd_numbers = filter(lambda n: n % 2 == 1, numbers)squared_odd_numbers = map(lambda n: n * n, odd_numbers)total = reduce(lambda acc, n: acc + n, squared_odd_numbers)
There are a few important points of syntax to highlight.
filter()are natively available. However,
reduce()must be imported from the
functoolslibrary in Python 3+.
- The lambda expression is the first argument in all three functions while the iterable is the second argument
- The lambda expression for
reduce()requires two arguments: the accumulator (the value that is passed to each element) and the individual element itself.