Python Tales - The Python Tutor Blog

A Python Programming Blog, from a Pythoneer to Pythoneers, created by The Python Tutor.

Tuesday, May 16, 2017

A Tale on Python List and Functions II - Lambda, map, reduce and filter

Hello my Pythoneers, now we have come to the awesome part of List, where we can make cool things applying Map, Filter, Reduce. If you just came here and did not see the last part here I give a link on Part I. So now let's begin with the first Built-in function.


What is map? Map is a Python Built-in function that we can use to apply another function on each element of a sequence to produce another sequence. I see, what is so cool about this? Well you significantly reduce your amount of code by creating new list without iterating over others. But this code reduction is not achieved if we don't cover first anonymous functions, wait what? Anonymous?

Anonymous Functions

Anonymous functions are those functions that can be created in line with the code that requires a function to be executed. Normally functions are defined by using a name to differentiate it from variables and other functions, anonymous functions doesn't required this name specification (I think that's why they are called anonymous). So how do I implement anonymous functions on Python? That is making use of the lambda statement, as the example below
>>> f1 = lambda x: x ** 0.5
>>> f1(4)
>>> f1(9)

As you can see, we are using the lambda statement, to anonymously create a function that calculates the square root of the function's argument, we implement this by stating all the variables required right before the semicolon (:), for more than one variable we use the argument separator character, comma (,), and after the semicolon the function body, this needs to be a one line statement, you can implement if-else structure but in one line.
But as you can see I assigned this to a variable named f1, you would ask, isn't this the same as defining? Is not so much anonymously. Well for this example that is correct, but let's now show an example where we can make an anonymous use but with the use of the map function. In the next example we are going to create a new list of the square roots from another list
>>> listA = [4, 9, 16, 25, 36]
>>> listB = map(lambda x: x ** 0.5, listA)
>>> listB
[2.0, 3.0, 4.0, 5.0, 6.0]

Got it? Well let me explain it a little, the map function has the following in the arguments, map(function, sequence), you can pass a function name to the function argument, but also you can create a in line anonymous function with the lambda statement, the map function will map the function on each element of the sequence (I think that's why is called map). We can apply functions as we require, there is no limit in implementing it with other data types and values, for instance what about if we want to lowercase every element in a string sequence? For sure we can do that also.
>>> NAMES = ["Tony", "STEVE", "Peter", "BruCE", "NatASHA"]
>>> names = map(lambda y: y.lower(), NAMES)
>>> names
['tony', 'steve', 'peter', 'bruce', 'natasha']

Pretty cool right? Well you would probably think maybe not, but wait we still have some other functions to learn, let's cover now Filter.


What is filter? Filter as the name kind of explain it self, is similar to map but this case we want to only create a new list from another in which the function applied on each element returns true. So let's see an example.
>>> numbers = list(range(40))
>>> even_numbers = filter(lambda z: z % 2 == 0, numbers)
>>> even_numbers
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38]

As you can see, we used the filter function to take the even numbers for a sequence of number, from 0 to 39, the lambda statement now uses a Boolean operator to return either True or False, but only those numbers from the sequence that return True, are gathered to create a new list. Still thinking this is not cool? Well let's see another example in which we only select the leap-years from a sequence of year numbers from 1800 to 2000.
>>> years = range(1800, 2001)
>>> leap_years = filter(lambda x: False if not x % 4 == 0 else True if not x % 100 == 0 else False if not x % 400 == 0 else True, years)
>>> leap_years
[1804, 1808, 1812, 1816, 1820, 1824, 1828, 1832, 1836, 1840, 1844, 1848, 1852, 1856, 1860, 1864, 1868, 1872, 1876, 1880, 1884, 1888, 1892, 1896, 1904, 1908, 1912, 1916, 1920, 1924, 1928, 1932, 1936, 1940, 1944, 1948, 1952, 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000]

How about now? Still no thinking this pretty cool? In this case we introduced something new so far, and that is ternary operator, and this is a one line If-Else statement, which has the following structure, value_if_true if condition1 else value_if_false, this is kind of tricky but with practice you will master it, you can also as in the example chain a ternary operator inside either the value of True or False. Now let's take a look at the final function which is Reduce.


This function has the same structure as Map and Filter, we take as first argument a function, and as second argument a sequence, but the main difference is that this function doesn't return a sequence, instead it returns a computation, it reduces the incoming sequence to a final single value. The structure of the function passed, must take two arguments and return a single value of the computation of those two arguments, this will be applied to elements at time in the sequence provided to the reduce function, a thing to point is in Python 2 this function is already imported since it is a Built-in function, but for Python 3 this function needs to be imported from the functools module, now let's see an example.
>>> list_of_sets = [{2, 4, 6, 8, 10}, {1, 2, 3, 4, 8, 10}, {1, 2, 5, 8}]
>>> intersections = reduce(set.intersection, list_of_sets)
>>> intersections
set([8, 2])

in this example we instead of using lambda we used a method from a Python Data Type, I make this so you can see that we can provide any function to map, filter or reduce, they can be defined functions, anonymous functions, built-in functions or even object methods, but the must take two arguments and produce one output, the intersection methods takes two sets and creates a new set in the common values in both of them, but if we have several sets in a list, we can reduce the list instead of iterating with for loops, pretty cool right?
In a later entry I will show you how you can combine and chain Map, Reduce and Filter to create awesome outputs, but this is a programming paradigm called Functional Programming that we will discuss in more detail later. So thanks for coming by my new entry and I hope you have enjoyed this as much as I enjoyed writing it, stop by the comments if you want to discuss about this.