Python map(function, iterable, ...)
LearnDataSci is reader-supported. When you purchase through links on our site, earned commissions help support our team of writers, researchers, and designers at no extra cost to you.
map()
is a function implemented by many modern programming languages that's used to transform data collections.
Here's a quick example that uses map()
to square all integers in a list:
Here, we used a lambda function to do the squaring. Also, since map()
is part of Python's standard library, we can use it without an import statement.
For the rest of the article, we'll go deeper into how map()
works and provide many unique examples to demonstrate its functionality.
A Quick Overview
map()
applies a function to each element of a collection (_or_ multiple collections), but an iterator is returned instead of performing the work right away. In the intro example above, we materialized the results of squaring each element by converting the results to a list with list(squared)
, but iterating over results in a loop also works.
Example
Let's look at another quick example. Assume we have a words
list, and we want to calculate the length of each word to populate a word_lengths
list. First, we'll split a string into words, then map the len()
function to the collection, like so:
map()
returns a map object, which is an iterator. Here, we materialized this middle product (the_iterator
) into a list and printed the result.
For loop equivalent
This transformation we made in essentially two lines of code does the job of the for loop given below:
As you can see, map()
is the shorter, more readable alternative for transforming data collections.
User-Defined Functions
In the previous section, we called map()
with the built-in len
, but we can also create our own functions.
In the following code block, we created a function that calculates the factorial of a number, n
.
The factorial()
function returns 1 when n
is 1—this is the base case. Otherwise, it recursively calls itself on (n-1)
until it reaches the base case.
Let's try and use them with map()
:
For this example, we evaluated the iterator in a for-loop by printing each value. Note that the factorial for each number is calculated lazily, so only one number at a time is processed.
Lambda expressions
Let's make a function that determines if a number is even. The following will return the number passed in along with whether or not the number is divisible by two without a remainder.
We can then map the function onto an iterable of numbers, like so:
For these types of small operations, we can use _lambda expressions_, which let us define one-expression-long functions in place. They look something like this:
Lambdas take any number of parameters but are restricted to holding only one expression. We can pass the functionality of is_even()
directly to map()
using a lambda expression, like so:
Lambdas can be an excellent tool for simple scripts and quick data manipulation, but they can also be less readable and harder to maintain in larger projects.
Calling map() on Multiple Iterables
map()
can accept any number of iterables if the passed function has the same number of parameters. Until now, we used it with one iterable and passed in a one-parameter function. To use it with _n_ iterables, we must pass an _n_-parameter function.
Let's try and derive BMIs (Body Mass Index) from a list of heights and a list of weights using map()
. First, we'll define some data for three people:
In the above data, index zero corresponds to person one, who has a weight of 120kg and a height of 1.90 meters.
We want to create a function that calculates $BMI = \frac{weight}{height^2}$ and map it to each person. We'll use a lambda expression that takes two parameters for the calculation and then pass in both weights
and heights
to map()
:
Given a function and multiple iterables as parameters, map()
matches the nth iterable to the function's nth parameter. Here weights
are given to x
and heights
are given to y
.
Iterables of different lengths
In the BMI example, we used map()
with multiple iterables of equal length. Let's see what happens if we try to use iterables of different lengths.
We will use three lists: one holding adjectives, one holding colors, and the other holding object names. We will try and compose short object definitions:
Here, map()
takes in three lists of different sizes and a lambda expression that concatenates three values using an f-string.
Notice that map()
could only execute the lambda function three times. Because after the third time, the adjectives
list was exhausted, and the lambda couldn't get all three required parameters.
Using map() with single parameters
Suppose we want to raise all numbers in a list to a specific power, but we want the power to be a parameter. For example:
And we now want to use this function to square numbers from 1–5:
map()
only expects iterables as arguments, so '2' being an int
won't work. Instead, we need to make an iterable of 2s of equal length to the numbers
. We easily achieve this by using the repeat
function from the itertools
module:
repeat
converted our '2' into an infinite iterable of 2s, allowing map()
to function as expected. There are many helpful tools in the itertools
module for functional programming; see the docs for more.
Alternatives to map()
List comprehensions and generator expressions solve similar problems to map()
. The general syntax for both are as follows:
The only syntax difference between the two is that list comprehensions use square brackets, and generator expressions use parentheses. The functional difference between them is that generator expressions return a generator, which waits until iteration before performing any work.
For comparison, the code below shows a list comprehension and map()
raising a set of numbers to the power of two.
List comprehensions
List comprehensions also allow filtering by adding an if
. Here's how we'd filter the previous list comprehension and transform only the numbers that are even:
That said, we do have access to something similar for map()
with the filter
function:
It starts getting confusing with this many layers, so it's atypical to see this in public projects. The main benefit of the above example is that no work was performed until we materialized the list in the print statement.
A list comprehension returns an iterable, which holds values, whereas map()
returns iterators, which hold logic and produce the values on demand. This matters with larger datasets since we need to store all values in memory.
Generator expressions
The issue of list comprehensions having to keep values in memory can be mitigated by using generator expressions, which, like map()
, also produce iterators.
Generator expressions save memory, allow filtering, and are more readable, which makes them the closest competition to map()
. Most programmers view choosing one over the other as a matter of personal preference. Check out this Stackoverflow post to read what others think: List comprehension vs map.
Summary
Python's built-in map()
function takes in any number of iterables along with a function that operates on the same number of parameters. map()
applies the function to every element of the iterables and populates an iterator with the return values.