Saturday, 17 December 2016

Python map() Function

Python map() function - Many of times, we may require to execute same operation on different elements of a sequence. For this, we create an empty list, write a for loop, perform the operation and append result in the list. Python provides a built-in function - map(), to perform the similar operation. It receives at least two arguments - a function and one or more iterable objects, applies the function on each item of the iterables and returns a list with results of the operation. When we say, map() accepts function as an argument, it may be a built-in function or a normal function created using def construct or it can be a lambda. We will be learning how each of them can be used in the map function. But, I recommend you to have a read over our article on Python lambda function, if you haven't already.


Python map() function

As mentioned above, the map() function accepts a function (without parenthesis) and one or more iterables as arguments. So, we can write its syntax as below:

Syntax:

map(function, iterable1, iterable2, ...)

Example 1 : Converting an integer to binary equivalent, with built-in function 'bin()'

>>> myList = range(1, 11)

>>> myList
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

>>> print map(bin, myList)
['0b1', '0b10', '0b11', '0b100', '0b101', '0b110', '0b111', '0b1000', '0b1001', '0b1010']

In above example, map function takes a function bin() (without parenthesis), which returns binary equivalent of a number, and a list myList. It applies bin() function on every list item and returns a list of result values. If this seems confusing, we take another example. Before that, we see what we would have done, if we weren't aware about map() function - a for loop may be.

# Create a list of numbers
>>> myList = range(1, 11)
>>> myList
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Create an empty list to store the result
>>> result = []

# Iterate over each item, run 'bin()' function on it and append result to 'result' list
>>> for num in myList:
...     result.append(bin(num))
...

>>> print result
['0b1', '0b10', '0b11', '0b100', '0b101', '0b110', '0b111', '0b1000', '0b1001', '0b1010']

Example 2: Square root of numbers using 'math.sqrt()' function

# Create a list
>>> myList = range(1,6)
>>> myList
[1, 2, 3, 4, 5]

# Import 'math' module
>>> import math

# Run 'math.sqrt()' on each list item
>>> print map(math.sqrt, myList)
[1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979]

Simple, isn't it? We just had to import math module, in order to use sqrt() function within a map() function. Now, we create a function using def and use it in map(). Our function cube() accepts an argument and returns it's cube i.e. it's 3rd power.

Example 3 : Cube of numbers using 'cube()' function created using def

# Define the function
>>> def cube(num):
...     return num ** 3
...

# Create a list
>>> myList = range(1, 11)
>>> myList
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Use function and list in 'map()' function
>>> map(cube, myList)
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

Another example we take, in which we determine if a number in a list is even or odd. This would be a very simple function to create, which returns 'Even' or 'Odd' as per the input received.

Example 4: Determining a number is Even or Odd

# Create the test data
>>> myList = range(1, 11)
>>> myList
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Create our 'evenOdd()' function
>>> def evenOdd(num) :
...     if num % 2 == 0:
...             return'Even'
...     return 'Odd'
...

# Use them in 'map()' function
>>> print map(evenOdd, myList)
['Odd', 'Even', 'Odd', 'Even', 'Odd', 'Even', 'Odd', 'Even', 'Odd', 'Even']

As we have seen in our article on lambdas, lambdas return a function type. So, we can use them in map() function also.

Example 5: Determine whether a number is perfectly divisible by 5

# Create a list of numbers
>>> myList = range(1, 21, 3)
>>> myList
[1, 4, 7, 10, 13, 16, 19]

# Crate a lambda function and assign it to the name 'div5'.
# Function should return 'Yes' if number is divisible by 5, else 'No'
>>> div5 = lambda num : 'Yes' if (num % 5 == 0) else 'No'

# Use 'div5()' and 'myList' in 'map()' function
>>> print map(div5, myList)
['No', 'No', 'No', 'Yes', 'No', 'No', 'No']

Instead of assigning a lambda to a name, we can directly use it in map(), as it returns a function object, as shown below.

# lambda function as the argument
>>> print map(lambda num : 'Yes' if (num % 5 == 0) else 'No', myList)
['No', 'No', 'No', 'Yes', 'No', 'No', 'No']

We can also provide multiple iterable objects to map() functions. In this case, items from all iterables are taken in parallel to create a sequence and the sequence is provided as arguments to the function. Seems confusing? Lets create three lists and let our function be a lambda that returns a tuple of the arguments provided. As a result, we get a list of tuples.

# We create three lists
>>> numList = [1, 2, 3, 4]
>>> strList = ['One', 'Two', 'Three', 'Four']
>>> rankList = ['1st', '2nd', '3rd', '4th']

# lambda function that returns a tuple of it's arguments
>>> lambda x, y, z : (x, y, z)

# Using them in 'map()' function
>>> map(lambda x, y, z : (x, y, z), numList, strList, rankList)
[(1, 'One', '1st'), (2, 'Two', '2nd'), (3, 'Three', '3rd'), (4, 'Four', '4th')]

In this way, an item each from every list is taken out in parallel and the sequences L1[0], L2[0], L3[0], L1[1], L2[1], L3[1], etc. are provided as arguments to the function. If the lengths of the lists are unequal, None would be passed as an argument.

# 'rankList' has 5 elements now, 'numList' and 'strList' have 4 each
>>> rankList = ['1st', '2nd', '3rd', '4th', '5th']

>>> map(lambda x, y, z : (x, y, z), numList, strList, rankList)
[(1, 'One', '1st'), (2, 'Two', '2nd'), (3, 'Three', '3rd'), (4, 'Four', '4th'), (None, None, '5th')]

map() inside another map() - As we know, map() function accepts list as one of the arguments and returns a list. So, we can use a list returned by a map() function as an argument to another map() function, so that there will be nesting of two map() functions.

# Create a list of numbers
>>> myList = range(1,11)
>>> myList
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Import 'math' module
>>> import math

# First 'map()' function calculate square root of each number
>>> map(math.sqrt, myList)
[1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979, 2.449489742783178, 2.6457513110645907, 2.8284271247461903, 3.0, 3.1622776601683795]

# Second 'map()' function will covert float to integer using 'int()' function
>>> print map(int, map(math.sqrt, myList) )
[1, 1, 1, 2, 2, 2, 2, 2, 3, 3]

We now close our discussion on Python map() function. We have learned how a function, may it be built-in or created using def or lambda, can be applied on one or more iterable objects in an efficient way, thus avoiding use of for loops. In the next article, we learn about another important function used in functional programming - reduce() function. Please share your views and feedback in the comment section below and stay tuned. Thank you!

0 comments:

Post a Comment