Advanced collections

Day 22: Exercise Solutions

Python Guru with a screen instead of a face, typing on a computer keyboard with a blue background to match the day 22 image.

Here are our solutions for the day 22 exercises in the 30 Days of Python series. Make sure you try the exercises yourself before checking out the solutions!

1) Below you'll find a list containing several tuples full of numbers. Use the map function to find the sum of the numbers in each tuple. Use manual iteration to print the first two results provided by the resulting map object.

numbers = [(23, 3, 56), (98, 1034, 54), (254, 344, 5), (45, 2), (122, 63, 74)]

First things first, lets create our map object. In this case we don't need anything complicated like a lambda expression or something from the operator module: we can just use the sum function.

numbers = [(23, 3, 56), (98, 1034, 54), (254, 344, 5), (45, 2), (122, 63, 74)]
totals = map(sum, numbers)

Now that we have a map object assigned to totals, we just need to pass this map object to next to get an item out of it. This is possible because map objects are iterators.

numbers = [(23, 3, 56), (98, 1034, 54), (254, 344, 5), (45, 2), (122, 63, 74)]
totals = map(sum, numbers)

print(next(totals))  # 82
print(next(totals))  # 1186

Note that the last three sums haven't been calculated at this point.

2) Write a program to create a schedule that lists which of your employees will lock up the shop on a given day over a 30 day period. You should list the day number, the employee name, and the day of the week.

For this exercise, we've been told that we have three employees that will take turns to lock up the shop each night. For example, if we start with employee A, they will close up on the first day, then employee B, followed by employee C. The cycle then starts over on day 4 with employee A.

In order to create this cycling behaviour we're going to be using a very useful function in the itertools module called cycle. cycle is a special type of iterator that will provide us an infinite number of results in some predefined sequence.

If we look at the documentation, we can see that the function signature looks like this:

itertools.cycle(iterable)

This tells us that cycle takes a single iterable which defines the values that should be cycled through.

With that in mind, let's import the module and create two cycle iterators: one for the employees, and one for the days of the week.

import itertools

employees = itertools.cycle(["Peter", "Fiona", "Carl"])
days = itertools.cycle(["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"])

Now that we have this, the rest of the solution is pretty simple. We just need to create a for loop that will have 30 iterations, which we can do by iterating over a range. We can then use the values in this range for the day numbers, and we can use next to keep grabbing values from the two cycles.

import itertools

employees = itertools.cycle(["Peter", "Fiona", "Carl"])
days = itertools.cycle(["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"])

for day_number in range(1, 31):
    print(f"Day {day_number} ({next(days)}): {next(employees)} closes.")

One of the really nice things about a solution like this is that we can add or remove employees by just modifying the list we pass into the employees cycle. We don't have to make any other changes.

import itertools

employees = itertools.cycle(["Peter", "Fiona", "Carl", "Helen"])
days = itertools.cycle(["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"])

for day_number in range(1, 31):
    print(f"Day {day_number} ({next(days)}): {next(employees)} closes.")

I think it would also be a good exercise to think about how you might do this without using any iterators.