 # How to Use Python Map() – An Efficient Way to Transform Data

This post introduces the reader to Python maps, implemented by the built-in map() function of Python.

Map is a powerful function that not only gives us new ways to transform data, but also aids us in reducing our code to just a few efficient lines in some select cases.

If you’re ready to bolster your Python programming skills, let’s dive in.

### Prerequisites

The reader is expected to have a working knowledge of Python programming.

We will be looking at using Python built in functions as well as custom functions in Python as an argument to the map function. The reader is therefore expected to also have written at least a few simple functions using Python, though previous knowledge of the built in function map is obviously not required.

The code in this example has been tested using Python 3.8.8 though the map function has been around much longer. The code hence will work with earlier versions of Python as well.

### What Python Maps are for

Map is an important function in the functional programming paradigm of Python. In functional programming, a function/set of functions operate on a piece of data to transform it. map is an excellent function to learn, to cut down on the amount of code that for loops take up.

If the data was a set of integers, examples of transformation on this data could include squaring the numbers, calculating their factorials, a Fibonacci sequence, etc. If the data were a set of sentences, we might consider stripping these sentences of punctuation. If the data were a set of words, we could capitalize the first letter of each word, etc.

### Syntax

map(function, iterable)

Map is a function that takes in a function and an iterable(s) and applies the function to every element of the iterable. Let’s look at an example of an iterable map object that squares every element of a list.

```def square(num) :
return num**2

>> sqr = map(square, [1,2,3,4,5])
>> print (sqr)
<map object at 0x7faa1d2483a0>

# convert map to list
>> print (list (sqr))
[1, 4, 9, 16, 25]```
1. square is a function that takes in a number and returns its square.
2. Call map passing in square as the function and the list [1,2,3,4,5] and assign the result to sqr.
3. Printing the value of sqr gives us a map object.
4. Convert this map object into a list and print its contents.
5. The result [1, 4, 9, 16, 25] is the list of squares of each individual element of the list.

The function passed to map as the first argument can also be an anonymous lambda expression. We get the same response by rewriting the above example as a lambda function:

```# square the numbers passed in
>>> sqr = map(lambda x: x*x, [1,2,3,4,5])
>>> list(sqr)
[1, 4, 9, 16, 25]

# capitalize the first letter of every word
>>> sentence = 'the curfew tolls the knell of the parting day'
>>> m = map(lambda word : word.upper() + word[0:] , sentence.split()))

>>> print(list(map))
['The', 'Curfew', 'Tolls', 'The', 'Knell', 'Of', 'The', 'Parting', 'Day']```

### Multiple iterables with map

The following example shows how multiple iterables can be passed to the map function. We call map, passing in the operator module and 2 lists.

```>> import operator
>> list(map(operator.mod, [4,6], [3,4]))

# output
>> [1, 2]```
1. Import the operator module.
2. Pass operator.mod and 2 lists to the map function. [4,6] contains the first argument to the mod function in the expression and [3,4] contains the 2nd argument. The two expressions being evaluated are 4%3 and 6%4.
3. The output list contains the remainders of the expression evaluation i.e. [1, 2] as expected.

When 2 iterables of different length are passed to map, the resultant iterable is only as long as the shorter iterable. Modifying the above example, we see this effect when the function iterates through.

```>>> list(map (operator.mod, [4,6,8], [3,4]))
[1, 2]```

We notice that the number 8 is ignored in the evaluation and the output result.

### Replacing a for loop with map

One of the most common uses of map is to replace a for loop of several lines with a single expression. The following example uses a for loop to check if corresponding items in a list are greater than or equal to numbers in another list and prints out a boolean list as result. The output list contains True where the comparison succeeded and False where it failed.

```import operator
boundaries  = [200, 30, 45]
numbers = [201, 31, 44]
result = []

# with a for loop
for idx in range(len(boundaries))  :
if numbers[idx] >= boundaries[idx] :
result.append(True)
else :
result.append(False)

print (result)
[True, True, False]

# syntax using map()
print (list(map(operator.ge,numbers,boundaries)))
[True, True, False]```
1. Import operator for use with map.
2. The boundaries list contains a list of numbers to compare against.
3. The numbers list contains the numbers that are being compared.
4. The result list will contain boolean values to indicate the success/failure of the comparison.
5. The for loop loops over the indices of boundaries and then compares corresponding elements of the numbers and boundaries lists.
6. If numbers[i] >= boundaries[i], True is appended to the result list. Otherwise False is appended.
7. After the for loop terminates, the result [True, True, False] is printed.
8. The same result i.e. [True, True, False], can be achieved with a single map call using operators.ge as the function and numbers and boundaries as the iterables. This shows the power of the map function. ### Comparing map() with List Comprehensionsand Generators

#### List Comprehension

A map expression can be replaced with a list comprehension which is more expressive. The square example above can be used as an example. The code in the list comprehension is seen to be more intuitive. It also automatically produces the list iterable without needing an explicit list() call like the map function does.

However, the list comprehension creates the list right away, adding memory and processing load up front whereas the map function does not do that.

```def square(num) :
return num**2

# using map
>> list(map(square, [1,2,3,4])

# can be replaced with a list comprehension
>> [square(x) for x in [1,2,3,4]]

# Output (in both cases):
[1,4,8,16]```

#### Generator

A generator can also be used in lieu of a map function call. Maps and generators both return an iterator and both need to be explicitly converted into a list. Both a generator and the result of the map call can be iterated over using the next() function. Thus, using a generator or a map call are not very different.

```def square(num) :
return num**2

# using map
list(map(square, [1,2,3,4])

# iterating using map
m =  map (square, [1,2,3,4)
i = iter(m)
>>> next(i)
1
>>> next(i)
4
>>> next(i)
9
>>> next(i)
16
>>> next(i)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

# can be replaced with a generator expression
list(square(x) for x in [1,2,3,4])

# iterating over the generator
>>> s = (square(x) for x in [1,2,3,4])
>>> s
<generator object <genexpr> at 0x7f6c303b6eb0>
>>> next(s)
1
>>> next(s)
4
>>> next(s)
9
>>> next(s)
16
>>> next(s)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

Output:
[1,4,9,16]```