Worked Examples: Comparisons and Flow Control#
These worked solutions correspond to the exercises on the Comparisons and Flow Control page.
How to use this notebook:
Try each exercise yourself first before looking at the solution
The code cells show both the code and its output
Download this notebook if you want to run and experiment with the code yourself
Your solution might look different - that’s fine as long as it gives the correct answer!
## Exercise 1: Fizzbuzz
Problem: Write a piece of code that can play fizzbuzz.
Your code should count from 1 to 100. Numbers that are divisible by 3 are replaced by “Fizz”; numbers that are divisible by 5 are replaced by “Buzz”; and numbers divisible by 3 and 5 are replaced by “Fizz Buzz”.
To generate the numbers from 1 to 100 you can use the range()
function with two numbers, to specify the start and end of your range, i.e. range(1,101)
.
Solution:
for i in range(1, 101):
if i % 3 == 0 and i % 5 == 0:
print("Fizz Buzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz Buzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
Fizz Buzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
Fizz Buzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
Fizz Buzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
Fizz Buzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
Fizz Buzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
Notes:
The modulo operator (%
):
i % 3
gives the remainder wheni
is divided by 3If
i % 3 == 0
, theni
is divisible by 3 (remainder is 0)Similarly for
i % 5 == 0
Order of conditions matters:
We check for divisibility by both 3 and 5 first
If we checked for 3 first, numbers like 15 would print “Fizz” and never reach “Fizz Buzz”
The conditions are evaluated top-to-bottom, and only the first
True
condition executes
The and
operator:
i % 3 == 0 and i % 5 == 0
isTrue
only when both conditions areTrue
This identifies numbers divisible by both 3 and 5 (i.e., divisible by 15)
Alternative Solution 1: Checking Divisibility by 15
Since numbers divisible by both 3 and 5 are divisible by 15, we can simplify:
for i in range(1, 101):
if i % 15 == 0:
print("Fizz Buzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
Alternative Solution 2: Building the Output String
Another approach is to build the output string sequentially by testing each condition separately:
for i in range(1, 101):
output = "" # Start with empty string
# Check if divisible by 3
if i % 3 == 0:
output += "Fizz"
# Check if divisible by 5
if i % 5 == 0:
if output: # If we already have "Fizz", add a space
output += " "
output += "Buzz"
# If output is still empty, use the number itself
if output == "":
output = str(i)
print(output)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz Buzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
Fizz Buzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
Fizz Buzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
Fizz Buzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
Fizz Buzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
Fizz Buzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
How this differs from the first solution:
Independent checks: We use separate
if
statements (notelif
), so both the “divisible by 3” and “divisible by 5” checks can execute in the same iteration.Building incrementally: Instead of deciding what to print all at once, we build the output string step by step:
Start with an empty string
Add “Fizz” if needed
Add “Buzz” if needed (with a space if “Fizz” is already there)
If nothing was added, use the number instead
The order still matters: We check divisibility by 3 first, then 5, so we get “Fizz Buzz” not “Buzz Fizz”.
No special case for 15: When a number is divisible by both 3 and 5:
First
if
block executes: adds “Fizz”Second
if
block executes: adds a space, then “Buzz”Result: “Fizz Buzz”
We don’t need a separate condition to check i % 3 == 0 and i % 5 == 0
because both blocks run automatically.
The space logic: In the divisibility by 5 block, we check
if output
: to decide whether to add a space:
If
output = "Fizz"
, we add a space before “Buzz” →"Fizz Buzz"
If
output = ""
, we don’t add a space →"Buzz"
(not" Buzz"
)
This pattern is particularly useful when you need to combine multiple conditions and you want the code to be easy to extend. For example, if the rules later changed to add “Pop” for numbers divisible by 7, you’d just add:
if i % 7 == 0:
if output:
output += " "
output += "Pop"
Alternative Solution 3: Building a List
Extending this idea, another approach is to use a list and the .join()
method to handle spacing automatically:
for i in range(1, 101):
output = [] # Build as a list instead of a string
if i % 3 == 0:
output.append('Fizz')
if i % 5 == 0:
output.append('Buzz')
# If the list is not empty, join the list elements with a space.
# If the list is empty, use the number
print(' '.join(output) if output else str(i))
Key idea: Build a list of words, then join them with spaces. The .join()
method handles the spacing automatically!
How it works:
Start with an empty list
[]
Add “Fizz” to the list if divisible by 3
Add “Buzz” to the list if divisible by 5
Join the list elements with
' '.join(output)
to create the final string
The magic of .join()
:
The .join()
method automatically puts spaces between list elements:
' '.join(['Fizz'])
\(\to\)"Fizz"
(single element: no space)' '.join(['Fizz', 'Buzz'])
\(\to\)"Fizz Buzz"
(two elements: space between)
This means we never need to check whether to add a space.
Advantages:
No conditional logic for spacing: The
.join()
method automatically handles when to add spaces—only between elements, never at the start or end.Most concise: At 7 lines (inside the loop), this is the shortest clear solution.
Common Python pattern: Building a list and joining is idiomatic Python for constructing strings from multiple parts.
Easy to extend: Want to add “Pop” for divisibility by 7? Just add another if
i % 7 == 0: output.append('Pop')
line.
Exercise 2: Solid, Liquid, or Gas?#
Problem: Given the following data on the standard melting and boiling points of various metals, determine their state (solid, liquid or gas) at \(500\,^{\circ}\) C.
metals = ['Fe', 'Al', 'Hg', 'Ti', 'Pb']
melting_points = [1811, 933, 234, 1941, 601] # in K
boiling_points = [3134, 2743, 630, 3560, 2022] # in K
Solution:
# Given data
metals = ['Fe', 'Al', 'Hg', 'Ti', 'Pb']
melting_points = [1811, 933, 234, 1941, 601] # in K
boiling_points = [3134, 2743, 630, 3560, 2022] # in K
# Temperature to check (convert from °C to K)
temp_celsius = 500
temp_kelvin = temp_celsius + 273.15
for i in range(len(metals)):
metal = metals[i]
mp = melting_points[i]
bp = boiling_points[i]
if temp_kelvin < mp:
phase = "solid"
elif temp_kelvin >= mp and temp_kelvin < bp:
phase = "liquid"
else:
phase = "gas"
print(f"{metal:3s}: {phase:6s}")
Fe : solid
Al : solid
Hg : gas
Ti : solid
Pb : liquid
Alternative Solution: Using zip()
Here’s a version that uses zip()
to iterate over all three lists simultaneously:
# Given data
metals = ['Fe', 'Al', 'Hg', 'Ti', 'Pb']
melting_points = [1811, 933, 234, 1941, 601] # in K
boiling_points = [3134, 2743, 630, 3560, 2022] # in K
# Temperature to check (convert from °C to K)
temp_celsius = 500
temp_kelvin = temp_celsius + 273.15
for metal, mp, bp in zip(metals, melting_points, boiling_points):
if temp_kelvin < mp:
phase = "solid"
elif temp_kelvin < bp: # We already know temp >= mp
phase = "liquid"
else:
phase = "gas"
print(f"{metal:3s}: {phase:6s}")
Fe : solid
Al : solid
Hg : gas
Ti : solid
Pb : liquid
Improvements in this version:
Using
zip()
: No need for indices. We work directly with values from all three lists simultaneouslySimplified second condition: We can write
elif temp_kelvin < bp
: instead ofelif temp_kelvin >= mp and temp_kelvin < bp
: because theelif
only executes if the firstif
wasFalse
, meaning we already knowtemp_kelvin >= mp
More readable: Direct access to
metal
,mp
, andbp
instead ofmetals[i]
,melting_points[i]
, etc.