map Python – map function examples

by Alex
map Python - map function examples

Python is a very broad language. It provides the ability to write code in both object-oriented style and functional style. One of the basic functional style tools that Python programming provides is map(). This is a function that applies any other function to all the elements of any sequence (or several). In this lesson, you will learn how and why to use it.

Functional Style in Python

Functional programming is a paradigm that views a program as a collection of functions (in the mathematical sense). A function is a block of code that takes input data, does some work, and returns a result. If a function has no side effects – it only affects the data it returns – it is called a pure function. If most of your functions are pure, that’s a good thing, because such functions create a more coherent architecture that’s easier to figure out, look for errors, make changes, and so on. An example of a pure function:


def pure(x):
y = x + 500
return y

Example of a function with a side effect:


def pure(x):
y = x + 500
print(y)
return y

This function has a side effect, because it not only performs operations on the arguments and returns their result, but also outputs to the console. The functional programming style is said to allow for simpler code to be written. In my experience, this is true, as long as it doesn’t get to any really complex tasks. Functional programming includes at least the following tools: – The ability to call a function for each element of a sequence separately. The output is a new sequence consisting of the results of element-by-element execution of a function. In Python, this is represented by map(). – It is possible to call a filter function (that implements a certain condition) for each element of the sequence separately. The output is a new sequence consisting only of elements that satisfy the filter conditions.

In Python it is represented by the function filter(). – It is possible to call the function for each element of the sequence separately, which accumulates a value. The output is a single value. In Python, this is represented by reduse(). – Closures are functions that remember their state. – Anonymous functions – functions without a name. Represented by the Python keyword lambda (lambda). Despite the fact that Python is focused primarily on the object-oriented style, it has other tools from the functional programming style, for example the Python zip() function, which combines multiple sequences, enumerate(), which returns index-element pairs, list inclusions and so on.

map Python

map in Python 3 is a function that takes another function and one or more iterated objects, applies the resulting function to the elements of the resulting iterated objects, and returns a special map object that is an iterator and contains the results. The easiest way to get results from an iterator is to convert it to a collection – use list(), set(), or tuple() The Python map() function has the following syntax:


map(function, iterable, [iterable_2, iterable_3, ...])

You can say that map() goes through collection items in a loop and applies the passed function at each iteration. Thus, the same thing can be done with a normal loop or a list value. The following three code snippets are identical in their execution results:


collection = range(10)
def my_func(x):
return x**4
print('map:', list(map(my_func, collection)))
print('list inclusion:', [my_func(x) for x in collection])
result = []
for item in collection:
result.append(my_func(item))
print('for:', result)
# output:
map: [0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561]
List inclusion: [0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561]
for: [0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561]

What makes map() advantageous is the speed of execution. The point is that this function doesn’t need to create copies of elements for calculations and, because of that, it’s often faster than the alternatives. In addition, you can postpone calculations if you don’t immediately convert the iterator into a sequence. Let’s increase the computational complexity and measure the speed of all three methods:


from time import time
collection = range(10 ** 7)
def my_func(x):
return x ** 4 ** 4
now = time()
tuple(map(my_func, collection))
print('map:', time() - now)
now = time()
[my_func(x) for x in collection]
print('list inclusion:', time() - now)
now = time()
result = []
for item in collection:
result.append(my_func(item))
print('for:', time() - now)
# output:
map: 134.0279233455658
List inclusion: 135.18106865882874
for: 97.16599297523499

As you can see, map() is faster than list inclusion. Another advantage is that map() can accept multiple collections. This is harder to do with other methods.

First argument: function

The first argument of the map() function is a function. It can be a built-in or a user-defined function, and anonymous functions are also suitable. Even a method can be passed as the first argument.

  • Built-in – these are the pre-created functions
  • Custom – those that are written by the programmer using the keyword def
  • Anonymous – the functions that don’t have a name, and they are declared with the lambda keyword
  • Methods – functions that belong to certain class objects

An example of map() with built-in functions


from math import sqrt
collection = range(10)
print(tuple(map(sqrt, collection)))
# output:
(0.0, 1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979, 2.449489742783178, 2.6457513110645907, 2.8284271247461903, 3.0)

Here we use the built-in sqrt function from the math module of the standard library. This function returns the root of a number.

An example of map() with user-defined functions


from random import randint
collection = [randint(100, 7000) for i in range(10)]
def my_func(var: int):
print(chr(var), end=' ')
set(map(my_func, collection))
# Output:
Ӈ ر ᣐ ᧒ Ɵ ؆ ణ ག ᘁ ᎋ

Here, we first fill the list with random integers between 100 and 7000. Then we define a user-defined function with the keyword def. It takes an integer number in the var parameter and prints a character in the terminal that corresponds to this number. The last command is to execute the custom function my_func to each element of the collection sequence using map(). Since the map function returns a map object, it must be converted to a sequence. In this case, the iterator is converted to a set using the built-in set() function. Note that the my_func function does not contain the word return – it uses only the side effect print. In that case the value is still returned, but it’s None. You can check this by printing the map() iterator:


from random import randint
collection = [randint(100, 7000) for i in range(10)]
def my_func(var: int):
print(chr(var), end=' ')
print('\n' + str(tuple(map(my_func, collection))))
# Output:
ᢢ ฌ Y ᄣ ͯ ݑ ᒀ 𐷛 ෍ ᄼ
(None, None, None, None, None, None, None, None, None, None)

Example map() with anonymous functions

A common use of map() is to pass a lambda function. These functions look as follows: lambda parameters: expression Lambda functions are usually used only once. You can take any number of arguments with them, and the value that will be returned is determined by the expression specified after the colon.


collection = range(10)
print(tuple(map(lambda x: x**x, collection)))
# Output:
(1, 1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489)

In this example, lambda takes one argument x and returns x to the power of x. As you can see, these functions work fine with map().

An example of map() with methods

Yes, methods are about object-oriented programming. But, that’s the beauty of Python, the approaches can be combined.


collection = range(10)
my_list = []
tuple(map(my_list.append, collection))
print(my_list)
# output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In this example we create a variable called my_list of type list. Then, in map(), we call that object’s .append() method, which adds items to the end of the list.

The second argument: an iterable object

The most common iterable type in Python is a list. This is because objects of this type are really handy. But, there are others: set, tuple, dictionary, string and others.


collection = range(10)
my_list = list(collection)
my_tuple = tuple(collection)
my_set = set(collection)
my_dict = dict(enumerate(collection))
my_str = [str(i) for i in collection]
result_list = list()
tuple(map(result_list.append, my_list))
tuple(map(result_list.append, my_tuple))
tuple(map(result_list.append, my_set))
tuple(map(result_list.append, my_dict))
tuple(map(result_list.append, my_str))
print(result_list)
# Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

Here you can see how the map() function worked with all of the above iterated data types.

Handling Multiple Iterations with map()

You can pass several iterable objects to map(). In this case, the elements of each will be passed to the function as positional arguments in the same order as you listed them in the map() call. Unfortunately, named arguments cannot be passed this way. If iterated objects are of different lengths, map() will iterate as many times as the shortest collection.


collection = range(10)
def my_func(x: int, y: int):
return x ** y
result_tuple = tuple(map(my_func, collection, collection))
print(result_tuple)
# output:
(1, 1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489)

In this example, we passed the same collection sequence twice and a user-defined function that takes two arguments and returns the first of them, taken to a degree equal to the second. You can make sure that the resulting collection contains the same number of items as the passed lists. Now an example with sequences of different lengths:


collection = range(10)
def my_func(x: int, y: int):
return (x, y)
result_tuple = tuple(map(my_func, collection, collection[:4:-1]))
print(result_tuple)
# Output:
((0, 9), (1, 8), (2, 7), (3, 6), (4, 5))

Here we pass in the second collection, which is half as long as the first. As you can see, the resulting tuple has only 5 elements.

Return value: iterator

The Python map() function returns a special map object, which is an iterator. As mentioned above, it can be converted into a list, set, or tuple using built-in functions:


collection = range(10)
def my_func(x: int, y: int):
return (x, y)
result = tuple(map(my_func, collection, collection[:4:-1]))
print('tuple:', result)
result = list(map(my_func, collection, collection[:4:-1]))
print('list:', result)
result = set(map(my_func, collection, collection[:4:-1]))
print('set:', result)
result = dict(enumerate(map(my_func, collection, collection[:4:-1]))
print('dict:', result)
# output:
tuple: ((0, 9), (1, 8), (2, 7), (3, 6), (4, 5))
list: [(0, 9), (1, 8), (2, 7), (3, 6), (4, 5)]
set: {(2, 7), (1, 8), (0, 9), (4, 5), (3, 6)}
dict: {0: (0, 9), 1: (1, 8), 2: (2, 7), 3: (3, 6), 4: (4, 5)}

And you can defer calculations to a less computationally-loaded place in your code, or calculate iterations one at a time when you need them:


collection = range(10)
def my_func(x: int, y: int):
return (x, y)
map_object = map(my_func, collection, collection[:4:-1])
print(map_object.__next__())
print(map_object.__next__())
print(map_object.__next__())
print(list(map_object))
# Output:
(0, 9)
(1, 8)
(2, 7)
[(3, 6), (4, 5)]

In this example, we performed three iterations one at a time using the .__next__() dander method, and then calculated all the remaining iterations using list().

MapReduce

MapReduce is a distributed computing model developed in Google corporation, applied in Big Data technologies for distributed computations over giant data arrays in nodes of computer clusters. MapReduce can be confidently called the main Big Data technology. The essence of MapReduce is to divide the information array into parts, process each part in a separate node in a distributed manner, and finally combine all the results. Today there are many different, both commercial and free products that use this distributed computing model: Apache Hadoop, Apache CouchDB, MongoDB, in NVIDIA GPUs using CUDA, MySpace Qizmt and others.

The authors of this model are Google employees Jeffrey and Sanjay Ghemawat, who took as a basis two functional programming procedures: map, which applies the desired function to each element of the sequence, and reduce, which combines the results of map. In other words, in simplified terms, this model consists of dividing an array of data into parts, then performing the same calculations on different servers with different parts of the array, and then merging the results of the calculations again. I suggest you conduct an experiment and recreate MapReduce on your own computer.

Writing MapReduce

Instead of using multiple servers, we will use processes. Processes are like independent programs which can be computed on different processor cores. For this we need the multiprocessing module of the standard library. In this module we have a Pool object which represents several processes. The Pool object has the .map() method, which is identical to the map() function we studied earlier.


from multiprocessing import Pool
from time import time
def l(x):
return x ** 1000
y = list(range(100000))
if __name__ == '__main__':
a = Pool()
now = time()
sum(list(a.map(l, y)))
print('Calculations in the process pool took:', time() - now)
now = time()
sum(list(map(l, y)))
print('Calculations in one process took:', time() - now)
# Output:
Calculations in the process pool took: 1.8741416931152344
Computation in one process took: 4.924708127975464

Here, the role of reduce, i.e. generalization of results, is taken by the sum() function, which calculates the sum of all elements of the sequence.

Related Posts

LEAVE A COMMENT