Functional programming is the basis of most modern Big Data processing systems. Before going forward to the course, it is important to master data processing techniques using a functional programming style. In this assignment, your task is to train yourselves in thinking in a functional way when processing data.
Many of the the tasks below are easy, but some are not and require many iterations (and extensive testing!) to get right. For some of them, you can find ready-made solutions on the internet. Even though it may be tempting, I advise you against copying and pasting them here, as you will regret it later on in the course. Wax on, wax off!
This assignment has a total of 110 points. For each function you define, you also need to define at least one working example.
fold
s and friends¶T(5+5pts): Implement reduceL
and reduceR
using iteration for lists/arrays
def reduceL(someList, init, func):
for items in someList:
init = func(init, items)
return init
def reduceR(someList, init, func):
length = len(someList)
for i in range(1, length+1):
init = func(someList[length - i], init)
return init
def total_val(x, y):
return x * 1 /y
totalL = reduceL(range(1,10), 1, total_val)
print(totalL)
totalR = reduceR(range(1,10), 1, total_val)
print(totalR)
T (10pts): Implement reduceL
by reusing reduceR
def reduceL2(someList, init, func):
return reduceR(list(reversed(someList)), init, lambda x, y: func(y, x))
totalL2 = reduceL2(range(1,10), 1, total_val)
print(totalL2)
T (10pts): Implement a function flatten(xs: [A]): [A]
that converts a list of
lists into a list formed by the elements of these lists. For example:
>>> a = [[1,2],[2,3],[3,[4]]]
>>> flatten(a)
[1,2,2,3,3,[4]]
a = [[1,2],[2,3],[3,[4]]]
print(a)
def flatten(someList):
toReturn = []
for aList in someList:
for item in aList:
toReturn.append(item)
return toReturn
result = flatten(a)
print(result)
T (10pts): You may have noticed that the origianl flatten
definition is not
recursive, as it will only flatten 1 level nested lists.
Write a function deep_flatten(xs: [A]): [A]
that converts a list of
lists into a list formed by the elements of these lists recursively.
For example:
>>> a = [[1,2],[2,3],[3,[4]]]
>>> flatten(a)
[1,2,2,3,3,4]
a = [[1,2],[2,3],[3,[4, [5, 6, [ 4, 6]]]]]
print(a)
def deep_flatten(someList):
toReturn = []
for aList in someList:
for item in aList:
if type(item) is list:
toReturn = toReturn + deep_flatten([item])
else:
toReturn.append(item)
return toReturn
result = deep_flatten(a)
print(result)
T (10pts): Implement group_by
by reusing reduceL
.
def group_by(someList, theKeyFunction):
def helpme(someDictionary, item):
key = theKeyFunction(item)
if key in someDictionary.keys():
someDictionary[key].append(item)
else:
someDictionary[key] = [item]
return someDictionary
return reduceL(someList, dict(), helpme)
def number_classifier(number):
if number % 2 == 0:
return "even"
else:
return "odd"
a = [1,2,3,4,5,6,7,8,9]
final = group_by(a, number_classifier)
print(final)
From this point forward, use the reduceL
, reduceR
or flatten
implementations you created above.
T (5pts): Implement distinct
using reduceL
. Write its function signature.
# distinct(xs:[A]): [A]
def distinct(someList):
def addDistinct(someList, item):
if item not in someList:
someList.append(item)
return someList
return reduceL(someList, [], addDistinct)
a = [1,2,3,1,2,3,4,5,6,5,4,3,2,1]
final = distinct(a)
print(final)
T (10pts): Implement a function reverse
that reverses a list/array. As an
example:
>>> a = [1,2,3,4]
>>> reverse(a)
[4,3,2,1]
Also, write down the function signature.
# reverse(xs:[A]): [A]
def reverse(someList):
def helper(x, y):
y.append(x)
return y
return reduceR(someList, [], helper)
a = [1,2,3,4]
final = reverse(a)
print(final)
T (5pts): Implement a function mean
that calculates the mean of an list
of integers.
Also, write down the function signature.
# mean(xs:[A]): A
def mean(someList):
theSum = reduceL(someList, 0, lambda x,y: x+y)
elementsInList = reduceL(someList, 0, lambda x,y: x+1)
return theSum/elementsInList
a = [1,2,3,4]
final = mean(a)
print(final)
T (10pts): Implement a function called drop_while(xs: [A], f: A -> Boolean) : [A]
that drops the longest prefix of elements from xs
that satisfy f
.
>>> a = [1,2,3,4,5,6]
>>> dropWhile(a, lambda x: x <= 3)
[4,5,6]
def drop_while(someList, evaluate):
def helper(x, y):
if type(x) is not list:
if not evaluate(y):
return [y]
return x
else:
x.append(y)
return x
return reduceL(someList, -1, helper)
a = [1,2,5,3,4,5,6]
result = drop_while(a, lambda x: x <= 3)
print(result)
T (10pts): Implement a function zip(xs: [A], ys: [B]): List[(A,B)]
that returns a list formed from this list and another list by combining the corresponding elements in pairs. If one of the two lists is longer
than the other, its remaining elements are ignored.
>>> a = [2,3,4]
>>> b = [a,b,c,d]
>>> zip(a,b)
[[2,a],[3,b],[4,c]]
def zip(someList, otherList):
def helper(x,y): # x = [2,3,4] , y = [a,b,c,d]
stopping = True
while stopping:
for i in range(0,len(x)):
if type(x[i]) is not list:
x[i] = [i, y]
stopping = False
break
stopping = False
return x
return reduceL(otherList, someList, helper)
a = [2,3,4]
b = ['a','b','c','d']
final = zip(a,b)
print(final);
T (10pts): Implement a function
scanL(xs: [A], init: B, f: (acc: B, x: A) -> B) -> [B]
that works like reduceL
but instead of producing one final result, it also
returns all the intermediate results.
>>> a = [2,3,4]
>>> scanL(a, 0, lambda x, y: x + y)
[0, 2, 5, 9]
def scanL(someList, init, someFunc):
def helper(x , y):
x.append(someFunc(x[-1], y))
return x
return reduceL(someList, [init], helper)
a = [2,3,4]
result = scanL(a, 0, lambda x, y: x + y)
print(result)