# Functional Programming in Python — lambda, filter, map, reduce, and zip

Functional Programming uses calculations and computations as the evaluation of functions. It avoids state and mutable data that is characteristic for Imperative Programming. Functional programming is different from Object-Oriented Programming. There is no state in Functional, and it works with the data flow between functions only. There are no side-effects, so the execution of such functions does not affect state. Sometimes we need this behavior.

lambda param_list: expr

list(filter(func, list))

list(map(func, seq))

functools.reduce(func, seq)

list(zip(seq1 [,seq2,…]))

The name of the function lambda is from Lisp. Such a function is anonymous and is in one line. Thanks to the lambda statement we can create functions on the fly. In other words, we can create functions that are not bound to a name. Lambda can be used to replace several small functions, and thus save a lot of unnecessary code. It has the same scope rules as normal functions.

There can be default and named values, as well as *args and **kwargs.

def nazwa(param_list):
return expr

It’s the same as:

nazwa= lambda param_list: expr

The lambda is expression an expression and def is statement. We can place our lambda where we can place a normal expression. After def, we can include many statements, while the lambda body can include only one expression.

We can include the  whole function lambda in print:

>>> print((lambda x,y: x*y)(7,8))
56

We have the normal function:

>>> def myFunction(x):
…     return x*2

We have the result

>>> myFunction(4)
8
>>> myFunction(1)
2
>>> myFunction(34)
68
>>>

>>> var =  lambda x: x*2

We have the result:

>>> var(4)
8
>>> var(1)
2
>>> var(34)
68
>>>

Other version of our function lambda:

>>> (lambda x: x*2) (4)
8
>>> (lambda x: x*2) (1)
2
>>> (lambda x: x*2) (34)
68
>>>

Another example:

>>> var1 = lambda x,y: x+y

We have the result:

>>> var1(2,3)
5
>>> var1(565,345)
910
>>> var1(-23,45)
22
>>>

We can use lambda and other functions like filter(), map(), reduce() at the same time.

However, we should remember that there are some changes in Python 3.x.x. For example, let’s look at the lambda and filter in action:

>>> var2 = filter(lambda x: x%3 == 0, [1,2,3,4,5,6,7,8,9])

We have the result in variable var2, but when we try to see the result, we will get only the address in memory:

>>> var2
<filter object at 0x00C74330>
>>> print(var2)
<filter object at 0x00C74330>

We should use list to get the result:
>>> list(var2)
[3, 6, 9]
>>>

It works! Let’s try again. We have another example:

>>> mylist = [1,2,3,4,5,6,7,8,9]

>>> list(filter(lambda x: x%3 == 0, mylist))
[3, 6, 9]
>>>

So we can do that in one line only.

We can see that filter extracts each element in the sequence for which the function returns True. This function reduces a list to a single value by combining provided elements via a supplied function.

The lambda is especially useful with map() function. map() applies the function to all the elements of the sequence. As a consequence, it returns a new list with the elements changed by our function we passed to map().

>>> list(map(int, [’11’, ’12’, ‘456’]))
[11, 12, 456]
>>>

We should remember that map() can be applied to more than one list. The lists we will use in our code have to have the same length. Let’s see the example:

>>> x = [1,2,3,4,5]
>>> y = [1,2,3,4,5]
>>> z = [1,2,3,4,5]

We have the three lists, so now we can use map() with lambda:

>>> list(map(lambda x,y,z: x+y+z, x, y, z))
[3, 6, 9, 12, 15]
>>> list(map(lambda x,y,z: x-y-z, x, y, z))
[-1, -2, -3, -4, -5]
>>> list(map(lambda x,y,z: x*y*z, x, y, z))
[1, 8, 27, 64, 125]
>>>

We see that map() takes the first elements from all the lists, then — the second ones, the third ones, etc.

The function reduce() continually applies the function to the sequence seq. It returns a single value.

For example, we can determine the maximum of a list of numerical values by using reduce. We have the lambda expressions included in the variable zm:

>>> zm = lambda x,y: x if (x > y) else y

Now, we can use reduce(). We should remember that in Python 3.x.x the reduce() is included in functools, so we should import it first:

>>> import functools

Then, going with our function in this way:

>>> functools.reduce(zm, [34, 67, 459, 567, 34, 5, 6])
567

Let’s try with another example:

>>> functools.reduce(lambda x,y: x*y, range(5,10))
15120
>>>

It’s the same as:

>>> 5*6*7*8*9
15120

So we have just calculated the multiplication of the numbers from the range 5 to 10.

The function zip() accepts one or more sequences as arguments. It returns one list of tuples. Longer lists are cut to the shortest one.

seq1, seq2,…are sequences (strings, lists, or tuples).

list(zip([1,2,3,4,5]))

[(1,), (2,), (3,), (4), (5,)]

list(zip(“xyz”))

[(‘x’,), (‘y’,), (‘z’,)]

list(zip([1,2,3,4,5], “xyz”)

[(1, ‘x’), (2, ‘y’), (3, ‘z’)]

# apply isn’t used in Python 3.x.x, but in Python 2.x.x

The function apply() accepts a function, a tuple or a dictionary as an argument. It calls the function using the items in the tuple and the items in the dictionary as arguments treating them as keywords, and then returns the result of the called function.

apply(func [,args[,kwargs]])

func is a function or other callable object, args is the tuple with arguments that are passed to the func, and kwargs is the dictionary with arguments that are keywords sent to func. Keys have to be strings. We should know  that the calling:

apply(func, args, kwargs)

is the same as:

func(*args, **kwargs)

But:

apply(func, args)

isn’t the same as:

func(args)

The number of items in tuple equals to the number of arguments passed to function apply(func, args), while we pass only one argument in func(args); this argument is args tuple. arg can be every sequence (string, list, or tuple). If it isn’t a tuple, it will be changed into one.

apply(lambda x,y: x*y, (2,4))

8