The map(), filter(), reduce(), zip() and Lambda() funcion in Python
Some straightforward example to explain the function's glegance
About
Today I would like to share some straightforward example of these important built-in functions in Python:
They are some convenient function for us to deal with sequences, benefited by the world of functional programming, we can apply this functions into every single elements of a sequances, in order to reduce the time of explicit Loop. What's more, all this functions are pure function, both have return value, we can use this return value to repersent our expression.
So in layman term, why to use them is it cam much simplify our code, to execute those loop and iteration mission in a simple, elegance and efficient way.
map()
The map() function is going to return an iterator that applies function to every item of iterable, yielding the results. Such as list
we can check whether an object have iterable
attribute by using hasattr
such as:
> >> a = [1, 2, 3, 4]
>>> hasattr(a, '__iter__')
>>> True
- map() function simple syntex:
map(func, iterable)
* parameter:func
is an function thatmap()
pass to the every elements in theiterable
object, theiterable
is an object that has__iter__
attribute, so every elements can execute thefunc
- return value: a
map
object
Sounds like complicated? let's see an example:
Assume we have a list
that contain 1 - 5 digits, we want to every number add 1, before map()
function, most likely we will do this:
numbers = [1, 2, 3, 4, 5]
for i in range(0, len(numbers)):
numbers[i] += 1
print(numbers)
Or, in another way:
numbers = [1, 2, 3, 4, 5]
# create empty list
result = []
for n in numbers:
result.append(n+1)
print(result)
Obviously, no matter in which way, we all need to handle loop, so, we can try to use map()
function:
def add_one(n):
return n+1
numbers = [1, 2, 3, 4, 5]
result = map(add_one, numbers)
print(result)
print(type(result))
print(list(result))
I believe you already notice the beauty of map()
, we have achieved our purpose by not using loop, meanwhile, the code written in an elegent and simplicity way.
So the map()
function will return a map
object if we planning to use this object in the future, this object type will help us to save the memory utilization, we use the getsizeof()
function from sys
to see the memory utilization of each object, map
object and list
from sys import getsizeof
print(f'The size of map object in memory is {getsizeof(result)} bytes')
print(f'Convert it into list: {getsizeof(list(result))} bytes')
The requirement of object to passed in map()
function is iterable
so as long as the object has attribute of __iter__
it works, not only list
, but also tuple
, such as:
numbers = (1, 2, 3, 4, 5)
print(f"Is tuple numbers iterable? Answer: {hasattr(numbers, '__iter__')}")
result = map(add_one, numbers)
print(result)
print(type(result))
print(tuple(result))
Have you notice in order to achieved this, we need to create a function called add_one(n)
? and it just simply return n+1
, possible to reduce this? to make the code more simply and elegent? Yes, we can use lambda
numbers = (1, 2, 3, 4, 5)
result = map(lambda x: x + 1, numbers)
print(tuple(result))
Three lines of code, simple, elegent, Pythonic
Beside using defined function or lambda
function to execute the iterable, we also can utilize Python bulit-in function, bulit-in type to execute the iterable, such this case:
words = ['Singapore', 'Guangzhou', 'Tokyo']
# convert every elements in the array into List
converted = list(map(list, words))
print(converted)
print(f"The type of converted: {type(converted)}")
print(f"The lenght of converted: {len(converted)}")
words
is a list that contain string
type of elements, we can use map()
and Python bulit-in list
to convert every elements in words
into List, but do take note, every elements must have __iter__
attribute, otherwise, it will raise TypeError
, such as int
type:
numbers = [3, '23', 42]
print(list(map(list, numbers)))
We can see: TypeError
, int
object is not iterable, we can avoid it by this way:
numbers = [3, '23', 42]
print(list(map(float, numbers)))
filter()
filter()
function is using a function to "filter" the sequence, the function is going to examinate every elements in the sequence is True
or False
-
filter()
syntex:filter(func, iterable)
- Parameter:
func
test iterable sequances' elements isTrue
orFalse
,iterable
is the iterable sequances that been filter - Return value: an iterable sequance that every elements is
True
to the filter functionfunc
Layman term: filter()
is to filter a set of data based on the given conditions
Example:
def func(variable):
letters = ['a', 'e', 'i', 'o', 'u']
if (variable.lower() in letters):
return True
else:
return False
# given sequance
sequance = ['I', 'l', 'o', 'v', 'e', 'p', 'y', 't', 'h', 'o', 'n']
filtered = list(filter(func, sequance))
print(f"The vowel in the sequance is {filtered}")
Above we create a method to pull the vowel from a given sequance, the given sequance is List
, so it have '__iter__'
, and apply it to filter()
to pull out the vowel.
Here we have another example:
def positive(num):
if num > 0:
return True
else:
return False
# odd or even number
def even_number(num):
if num % 2 == 0:
return True
else:
return False
numbers = [1, -3, 5, -20, 0, 9, 12]
positive_number = list(filter(positive, numbers))
even_number = list(filter(even_number, numbers))
print(f"The positive number is: {positive_number}.")
print(f"The even number is {even_number}.")
So, how to use filter()
function is quite simple:
- define a method that can filter out
True
orFalse
- apply it to iterable object
- Integrate it into your bigger code block
Now let's see how to use lambda
together:
numbers = [0, 1, 2, -3, 5, -8, 42]
# odd number
odd_number = filter(lambda x: x % 2, numbers)
print(f"The odd number is {list(odd_number)}.")
# even number
even_number = filter(lambda x: x % 2 == 0, numbers)
print(f"The even number is {list(even_number)}.")
# positive number
positive_number = filter(lambda x: x > 0, numbers)
print(f"The positive number is {list(positive_number)}.")
Always remember the Python philosophy: efficient, simple, elegent
Reduce()
reduce()
is very useful built-in function, it can execuate iterable object's compuatation and return the result, it can rolling compute the continues values in an iterable sequance, such as cumulative product of integer list, or cumulative sum.
- Syntex:
reduce(func, iterable)
- Parameter:
func
: a continues method to execuate on each element of the iterable object, last resut is the new parameter of next execuation. - Return value: the
func
return value
In Python 3, reduce()
moved to functools
module, so before we use it, we need to import
it from functools
Example:
from functools import reduce
def do_sum(num1, num2):
return num1 + num2
print(f"The sum of 1, 2, 3, 4 is: {reduce(do_sum, [1, 2, 3, 4])}.")
def multiply(num1, num2):
return num1*num2
print(f"The cumulative product of 1, 2, 3, 4 is: {reduce(multiply, [1, 2, 3, 4])}.")
numbers = [1, 2, 3, 4]
result_multiply = reduce(lambda x, y: x*y, numbers)
result_sum = reduce(lambda x, y: x+y, numbers)
print(f"The cumulative product of 1, 2, 3, 4 is: {result_multiply}")
print(f"The cumulative sum of 1, 2, 3, 4 is: {result_sum}.")
zip()
As it's name, zip()
function is to put multiple iterable
object together, and "packed" it as one single object, mapping with similar index.
- Syntex:
zip(*iterators)
- Parameter:
iterators
isiterable
object, such asList
,String
- Return value: Single iterator object, containing index value from the packed object.
Example:
keys = ['name', 'age']
values = ['Apple', '44']
apple_dict = dict(zip(keys, values))
print(apple_dict)
zip()
it also support multiple objects:
names = ['Apple', 'Google', 'Microsoft']
ages = ['44', '21', '44']
values = ['100', '80', '60']
mapped_values = list(zip(names, ages, values))
print(mapped_values)
We can use the zip()
function to easily packed the values have same index from 3 list
But how about unpack?
Simple, just similar to unpanc tuple, we add the *
to the object that we want to unpack
names, ages, values = zip(*mapped_values)
print(f"The names is {names}")
print(f"The ages is {ages}")
print(f"The values is {values}")
lambda()
While normal functions are defined using the def
keyword, in Python anonymous functions are defined using the lambda
keyword. Hence, anonymous functions are also called lambda functions.
Lambda
function can use any quantity of parameter, but only have one expression
- Syntex:lambda argument: manipulate(argument)* Parameter: argument is the passing parameter, after the
:
is the manipulate
Example:
add_one = lambda x: x+1
add_sum = lambda x, y: x+y
print(add_one(2))
print(add_sum(5, 5))
Normally we will not use lambda
function individually, we will use it along with other built-in function or def
function, which we have already shows above, use it along with map()
, filter()
, reduce()
and zip()
function.
Let's see one more example of lambda
interacting with dict
university = [{'name': 'NYU',
'city': 'New York'},
{'name': 'NUS',
'city': "Singapore"}]
names = list(map(lambda x: x['name'], university))
print(names)
Above we interacting with dict
with map()
function, given the condition for the iterable list
of dict
that contain the name
and the city
of each University
We also can interacting dict
with filter()
function, through the return value True
or False
to judge the filtering condition.
university = [{'name': 'NYU',
'city': 'New York'},
{'name': 'NUS',
'city': "Singapore"}]
names = list(filter(lambda x: x['name'] == 'NUS', university))
print(names)
Through the above example, you have seen the actual application scenario of lambda
, but here I want to share my views with you: I think that the disadvantages of lambda
are slightly more than the advantages, and you should avoid overusing lambda
.
First of all, this is just my personal opinion. I hope everyone understands why I said this. First, let's compare the lambda
method with the conventional def
. I find that the main differences between lambda
and def
are as follows:
- Passing the parameter immediately(no need to define variable).
- one line of code, very simple (but, it doesn't mean is efficient).
- Automatically return, no need
return
keyword. -
lambda
function DO NOT have a function name
You can see the advantages. I mainly want to talk about its disadvantages. First of all, starting from real needs, we don’t need lambda
most of the time, because we can always find better alternatives. Now let ’s take a look In the example of lambda
+ reduce()
, the result we achieved with lambada
is as follows:
from functools import reduce
numbers = [1,2,3,4]
result_multiply = reduce((lambda x, y: x * y), numbers)
result_add = reduce((lambda x,y: x+y), numbers)
Above example, the lambda
didn't achieved the simple and efficient purpose, as we have the bulit-in sum
and mul
method, even it can work with NumPy
also
from functools import reduce
import operator
import numpy as np
numbers = [1, 2, 3, 4]
result_sum = sum(numbers)
result_multiply = reduce(operator.mul, numbers)
print(f"The sum is {result_sum}")
print(f"The cumulative product is: {result_multiply}")
matrixA = np.random.randn(3, 3)
matrixB = np.random.randn(3, 3)
matrixList = [matrixA, matrixB]
mulmat = reduce(operator.mul, matrixList)
print(f"The Matrix Multipication is \n {mulmat}")
The result is the same, but obviously the solution using sum
and mul
is more efficient. Another common example shows that if we have a list
that stores various colors, we now need to capitalize the first letter of each color. If we write it in lambda:
colors = ['red','purple','green','blue']
result = map(lambda c:c.capitalize(),colors)
print(list(result))
Seems ok, but, did we forgot the power of List
?
colors = ['red','purple','green','blue']
result = [c.capitalize() for c in colors]
print(result)
Sorted
can also handle the case of irregular initials, saving even more time:
colors = ['Red','purple','Green','blue']
print(sorted(colors,key=str.capitalize))
There is another reason: lambda
functions do not have function names. So in the case of code transfer and project migration, it will bring a lot of difficulties to the team. It is not bad to write a function add_one()
, because everyone is easy to understand and know that it is a function of performing +1
, but if you are in the team, use a lots of lambda
will make peoples confused.
Scenario that fit lambda
- Your method is too simple to have a name, such as adding 1, or just stiching the strings
- Using
lambda
is much easier for people to understand - There's no any Python built-in function except
lambda
- Team members are all well understand
lambda
, most importantly, no one complain you.