Lecture 13

Today:

  • Finishing up lambda, filter, map and reduce
  • Objects and classes

Lambda, map, reduce, filter

Recally lambda from last lecture:

f = lambda x,y,... : ...some_expression_using x and y ...

was a shortcut for a function defined by:

def f(x,y,...):
    return ...some_expression_using_x_y_...
In [1]:
f = lambda x: x*x
f(5)
Out[1]:
25
In [2]:
(lambda x,y : x + y)(2,5)
Out[2]:
7

lambda comes from Lambda Calculus, which was a model of computation that mathematicians thought about before computers existed. It was invented by Alonso Church (who was the advisor of Alan Turing)

Map

map(f,xs), returns: [f(xs[0]), f(xs[1]),...]. i.e. it applies f to each element of xs.

same as list comprehension:

[f(x) for x in xs]
In [3]:
from math import floor
list(map(floor, [1.234, 2.1234145, 3.42424, 4.525]))
Out[3]:
[1, 2, 3, 4]
In [4]:
[floor(x) for x in [1.234, 2.1234145, 3.42424, 4.525]]
Out[4]:
[1, 2, 3, 4]
In [5]:
list(map(lambda x: 2**x, range(15)))
Out[5]:
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384]

Compare with:

In [7]:
[2**x for x in range(15)]
Out[7]:
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384]

Filter

filter(f, xs) filters out the elements x in xs for which f(x) is False:

In [23]:
list(filter(lambda x: x % 3 == 1, range(20)))
Out[23]:
[1, 4, 7, 10, 13, 16, 19]
In [24]:
[x for x in range(20) if x % 3 == 1]
Out[24]:
[1, 4, 7, 10, 13, 16, 19]

Reduce

This is the one that's really new for us because it makes very nice one-liners, but it's in a library called functools. (it used to be standard in Python 2)

reduce(f, xs), takes a function f(x,y) of two variables, and applies the function first to x[0] and x[1], getting f(x[0], x[1]). And then applies f to f(x[0], x[1]) and x[2], getting f(f(x[0], x[1]), x[2]),...

In [25]:
from functools import reduce
reduce(lambda x, y: x+y, range(10))
Out[25]:
45

Let's see what happened:

lambda x, y: x+y is the addition function. range[10] is [0,1,2,3,4,5,6,7,8,9]

reduce(lambda x, y: x+y, range(10)) first computes 0+1, takes the result 1 and adds it to 2, then takes the result 3 and adds it to the next element 3.

In [26]:
reduce(lambda x, y: x*y, range(1,10))
Out[26]:
362880

$362880$ is $10!$


In [27]:
factorial = lambda n: reduce(lambda x, y : x*y, range(1,n))
In [28]:
factorial(10)
Out[28]:
362880

Do you remember the homework problem when we were supposed to write a function dupli(xs,k) that takes a list and returns the same list but with each element repeated k times:

In [29]:
xs = [1,2,4,1,2]
diplo = lambda xs, k: reduce(lambda x, y: x+y, map(lambda a: k*[a], xs))

# this is clearly not a good way to implement this function!! It's hard to read. 
# still, it's cool that we can do this and it's good exercise for the brain
diplo(xs, 3)
Out[29]:
[1, 1, 1, 2, 2, 2, 4, 4, 4, 1, 1, 1, 2, 2, 2]

Exercises

  • Using map and lambda, write a function that will take the square of each number in a list.
  • Using the above function and reduce, write a function that will return the Euclidean norm of a list/tuple. (i.e. $\sqrt{x_1^2 + ... + x_n^2}$)
  • Hard: What is the function apply(n,f,x) below doing?
In [30]:
apply = lambda n,f,x : reduce((lambda y, g : g(y)),([x] + n*[f]))
In [31]:
apply(4, lambda x: x*3, 3)
Out[31]:
243
In [32]:
apply(3, lambda x: x*x, 2)
Out[32]:
256