More Complex Functions
This discussion we're going to work on some more complicated exercises together to get more practice writing longer (or otherwise harder) functions in Python.
Exercise 1: Write a function reverse_dict
that takes in a dictionary d
and reverses it. Specifically, for every value v
in the dictionary, we want a mapping in the new dictionary that is v: ks
where ks
is a set containing all the keys that map to v
.
(solution below)
.
.
.
.
.
.
.
def reverse_dict(d):
new_d = {}
for v in d.values():
s = {k for k, v2 in d.items() if v2 == v}
new_d[v] = s
return new_d
reverse_dict({'a': 1, 'b': 2, 'c': 2})
In your next homework, you'll be asked to work with a dictionary by treating it as a simple directed graph. That is, you can "travel" from a key to its corresponding value, which might appear again in the dictionary as something you can travel from.
Exercise 2: Write a function edges
that takes in a dictionary d
and returns a dictionary that for each element in the dictionary (key or value) associates it with the number of elements you can get either to or from it.
For example, if
graph = {'a': 'b', 'b': 'd', 'c': 'd'}
then
edges(graph) = {'a': 1, 'b': 2, 'c': 1, 'd': 2}
since a
can reach b
, b
can be reached by a
and can reach d
, c
can reach d
, and d
can be reached by b
and c
.
(solution below)
.
.
.
.
.
.
.
def edges(g):
new_d = {}
for k, v in g.items():
if k in new_d.keys():
new_d[k] += 1
else:
new_d[k] = 1
if v != k: # don't count self edges twice
if v in new_d.keys():
new_d[v] += 1
else:
new_d[v] = 1
return new_d
graph = {'a': 'b', 'b': 'd', 'c': 'd'}
edges(graph)
Higher-order functions can be pretty hard to reason about. Let's do some practice sorting lists to get a sense of how higher order functions might be used and then write one for ourselves.
Remember the Python method list.sort()
has an optional parameter key
. key
is a function that takes in the elements of the list and returns a number (or any other value we can compare) and sorts based on this value.
Exercise 3: Given a list l1
of positive integers >= 10, sort them by their second digit. Then, given another list l2
of lowercase strings, sort them by the number of vowels ("a", "e", "i", "o", "u"). Lastly, given a third list l3
, use a suitable function to randomize the list.
(solution below)
.
.
.
.
.
.
.
l1 = [190, 72, 81, 1000, 934]
l2 = ['pizza', 'ice cream', 'pasta']
l3 = [1, 2, 3, 4, 5]
import random
def count_vowels(x):
# can also use x.count()
total = 0
for c in x:
if c == 'a' or c == 'e' or c == 'i' or c == 'o' or c == 'u':
total += 1
return total
l1.sort(key = lambda x : int(str(x)[1]))
l2.sort(key = count_vowels)
l3.sort(key = lambda x : random.random())
print(l1)
print(l2)
print(l3)
Exercise 4: Write a function sort_comp
that takes in a list l
and a function comp
. comp
will take in two elements from the list a
and b
and return -1, 0, or 1. If
comp(a,b) < 0
,
then assume a < b
comp(a,b) > 0
,
then assume a > b
comp(a,b) == 0
,
then assume a = b
(solution below)
.
.
.
.
.
.
.
def sort_comp(l, comp):
new_l = []
for elem in l:
i = 0
while i < len(new_l) and comp(elem, new_l[i]) >= 0:
i += 1
new_l.insert(i,elem)
return new_l
l = [1,4,2,3,5]
def comp_fun(a,b):
return a - b
sort_comp(l, comp_fun)