10.3. Solutions to Chapter 5 Exercises#

10.3.1. Exercise 1#

Suppose that we have the following list of numbers: list_of_numbers = [1,2,3]. Then we want to insert a list of numbers at position 1. For this we execute: list_of_numbers.insert(1, [30,40]). Do you think this is valid? Will this code produce any errors? What will happen after executing it? You can use the cell below to check your answer.

# write your code here
list_of_numbers = [1,2,3]
list_of_numbers.insert(1,[30,40])
list_of_numbers
[1, [30, 40], 2, 3]

As you can see, the code is correct and runs. But instead of adding these two elements separately in the list it adds the list as a single element at position 1.

10.3.2. Exercise 2#

Suppose that someone has given us the following list of wrongly mixed fermented food and drinks: fermented_food = ['milk', 'yoghurt', 'beer', 'cider', 'tempeh', 'sauerkraut', 'kefir']. Our task is to have the food in one list and the drinks in another one. Find a way to separate them by using list comprehension.

# write your code here
fermented_food = ['milk', 'yoghurt', 'beer', 'cider', 'tempeh', 'sauerkraut', 'kefir']
fermented_drinks = ['beer', 'milk', 'cider', 'kefir']
fermented_food = [x for x in fermented_food if x not in fermented_drinks]
fermented_food
['yoghurt', 'tempeh', 'sauerkraut']

10.3.3. Exercise 3#

You are given the following list of numbers: [10,20,24,45,30,10,32,20,14,8,9,12,24,20,12,3]. Write a function to find the first and last indices of a given key value (passed as argument) in a list. Hint: use loops and your own variables.

# write function here
def find_key(key, list_of_numbers):
    first_index = -1
    last_index = -1
    for index, element in enumerate(list_of_numbers):
        # first occurrences of element
        if element==key and first_index==-1:
            first_index = index
            last_index = index
        # other occurrences of the element
        elif element==key and first_index>=0:
            last_index=index
    return (first_index, last_index)
# write function calls here
list_of_numbers_2 = [10,20,24,45,30,10,32,20,14,8,9,12,24,20,12,3]
print(find_key(10, list_of_numbers_2))
(0, 5)

10.3.4. Exercise 4#

You are given the following list of numbers: [10,20,24,45,30,10,32,20,14,8,9,12,24,20,12,3]. Write a function to find the first and last indices of a given key value (passed as argument) in a list this time using the index() method. Hint: Function definition may look something like: def find_key_2(key, list). Also the function should return a tuple containing the first and last indices.

# write function here
def find_key_2(key, values_list):
    first_index = values_list.index(key)
    #remember that lists are passed by reference
    #if we reverse it, the original one will be reversed
    #for this reason we create a deep copy
    list_copy = values_list.copy()
    list_copy.reverse()
    second_index = len(values_list) - list_copy.index(key) - 1
    return (first_index, second_index)
# write code here
list_of_numbers_3 = [10,20,24,45,30,10,32,20,14,8,9,12,24,20,12,3]
print(find_key_2(10, list_of_numbers_3))
(0, 5)

10.3.5. Exercise 5#

Variables a and b mistakenly were assigned values a = 3 and b = 5. The correct version would be: a = 5 and b = 3. Use sequence unpacking to correct this. Hint: Think of inverting values in a tuple.

# write your code here
a = 3
b = 5
b, a = (a,b)
print('a =',a)
print('b =',b)
a = 5
b = 3

10.3.6. Exercise 6#

What happens when you make a shallow copy of a tuple and then add elements to one of the tuples? Where will the changes be reflected?

# write answer here - you can write code to test your reasoning as well
tuple_1 = (1,2,3)
tuple_2 = tuple_1 # tuple 2 points to the same memory space as tuple_1

print('Tuples before changes: ')
print('tuple_1', tuple_1)
print('tuple_2', tuple_2)
tuple_1+=(4,5)

print('Tuples after changes: ')
print('tuple_1', tuple_1)
print('tuple_2', tuple_2)
Tuples before changes: 
tuple_1 (1, 2, 3)
tuple_2 (1, 2, 3)
Tuples after changes: 
tuple_1 (1, 2, 3, 4, 5)
tuple_2 (1, 2, 3)

Recall that tuples are immutable, so when we add elements to it a new tuple is created in memory. So when we create a shallow copy of a tuple, we will have two identifiers pointing to the same memory space. If one of this tuples changes, then a new tuple is created and the identifier will point to the new memory space. But the other identifier will remain unchanged and will continue to point in the old tuple.

10.3.7. Exercise 7 (Optional)#

You are given a list of values: [1,2,3,4,5,6,7,8,9] and need to find which of the squares of any of the values are divisible by 2. Use a lambda expression to find out. Hint: the iterable of the map() function has to be used as input to the filter() function.

# write your code here
numbers=[1,2,3,4,5,6,7,8,9]
list(filter(lambda x: x%2==0, map(lambda x: x*x, numbers)))
[4, 16, 36, 64]

The map() function returns an iterable. In our case this iterable will have the squares of the elements in the numbers list. Each squared element is then checked against the lambda expression of the filter() function to single out the squares that are even.