Tuple and Set Exercises

Tuples and sets are useful tools to work with in Python. Tuples are particularly useful, and we're going to learn how to use (and create) some useful Python functions that use them.

But first, again, let's go over a warm-up exercise together.

Warm-up Exercise: Write a function list_to_tuple that takes in a list l and returns a tuple with the same elements in the same order.

In [1]:
# solution 1
def list_to_tuple(l):
    tup = () # empty tuple
    for elem in l:
        # () + () adds two tuple together
        # (elem,) is a single element tuple containing just elem
        tup = tup + (elem,)
    return tup

# solution 2
def list_to_tuple(l):
    return tuple(l)

list_to_tuple([1,2,3,4])
Out[1]:
(1, 2, 3, 4)

Exercise 1: Python has a function enumerate which takes in a list l and returns something that can generate the list
[(0, l[0]), (1, l[1]), ..., (len(l)-1,l[-1])]
that is, a list of tuples pairing indices with the corresponding elements. As an example:

In [2]:
list(enumerate(["a","b","c"]))
Out[2]:
[(0, 'a'), (1, 'b'), (2, 'c')]

Write a function enumerate_list which takes a list l and returns the list generated by list(enumerate(l)) without calling enumerate.

(solution below)

.

.

.

.

.

.

In [3]:
# solution
def enumerate_list(l):
    new_l = []
    for i in range(len(l)):
        new_l.append((i,l[i]))
    return new_l

enumerate_list(["a","b","c"])
Out[3]:
[(0, 'a'), (1, 'b'), (2, 'c')]

Exercise 2: Python also has a function zip that takes in any number of lists of the same length and returns something that can generate a list of tuples where the corresponding elements in each list are returned in order. For example:

In [4]:
list(zip(["A","B","C"],["a","b","c"]))
Out[4]:
[('A', 'a'), ('B', 'b'), ('C', 'c')]

Write a function zip_list that takes in two lists l1 and l2 and returns the list generated by list(zip(l1,l2)) without calling zip.:

(solution below)

.

.

.

.

.

.

In [5]:
# solution
def zip_list(l1, l2):
    new_l = []
    for i in range(len(l1)):
        new_l.append((l1[i],l2[i]))
    return new_l

zip_list(["A","B","C"],["a","b","c"])
Out[5]:
[('A', 'a'), ('B', 'b'), ('C', 'c')]

enumerate and zip can actually take in more than lists. They can also take in, for example, tuples and strings. How they work isn't too important right now (we'll learn more about it next week!) but you may be interested and knowing that you can loop through them:

In [6]:
l1 = ["A","B","C"]
l2 = ["a","b","c"]

for index, element in enumerate(l1):
    print("Element {} is {}".format(index, element))

print("")

for element1, element2 in zip(l1, l2):
    print("{} is paired with {}".format(element1, element2))
Element 0 is A
Element 1 is B
Element 2 is C

A is paired with a
B is paired with b
C is paired with c

Sets are particularly good when you often want to check if elements are contained in it. These next two exercises can give some examples.

Exercise 3: Write a function contains_all that takes in a list l and a set s and returns True if every element in l is contained in s and returns False otherwise.

(solution below)

.

.

.

.

.

.

In [7]:
# solution 1
def contains_all(l, s):
    for elem in l:
        if elem not in s:
            return False
    return True

# solution 2, if you know about Python subset operators
def contains_all(l, s):
    return set(l) <= s # subset

print(contains_all([1, 2, 2], {1, 2, 3}))
print(contains_all([1, 4], {1, 2, 3}))
True
False

Exercise 4: Write a function contains_half that takes in a list l and a set s and return True if at least half of the elements in l are contained in s and returns False otherwise.

(solution below)

.

.

.

.

.

.

In [8]:
# solution
def contains_half(l, s):
    count = 0
    for elem in l:
        if elem in s:
            count += 1
    return count >= len(l)/2

print(contains_half([1, 2, 3], {1, 2}))
print(contains_half([4], {1, 2}))
True
False

Exercise 5: Write a function prod that takes in two sets s1 and s2 and returns the (Cartesian) product of these two sets. That is, all tuples (e1, e2) where e1 is in s1 and e2 is in s2.

(solution below)

.

.

.

.

.

.

In [9]:
# solution 1 using loops
def prod(s1, s2):
    new_s = set()
    for e1 in s1:
        for e2 in s2:
            new_s.add((e1,e2))
    return new_s

# solution 2 using (set) comprehensions
def prod(s1, s2):
    return {(e1, e2) for e1 in s1 for e2 in s2}

prod((1,2,3),('a','b','c'))
Out[9]:
{(1, 'a'),
 (1, 'b'),
 (1, 'c'),
 (2, 'a'),
 (2, 'b'),
 (2, 'c'),
 (3, 'a'),
 (3, 'b'),
 (3, 'c')}