Worked Examples: Comparisons and Flow Control

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 when i is divided by 3

  • If i % 3 == 0, then i 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 is True only when both conditions are True

  • 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:

  1. Independent checks: We use separate if statements (not elif), so both the “divisible by 3” and “divisible by 5” checks can execute in the same iteration.

  2. 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

  1. The order still matters: We check divisibility by 3 first, then 5, so we get “Fizz Buzz” not “Buzz Fizz”.

  2. 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.

  1. 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 simultaneously

  • Simplified second condition: We can write elif temp_kelvin < bp: instead of elif temp_kelvin >= mp and temp_kelvin < bp: because the elif only executes if the first if was False, meaning we already know temp_kelvin >= mp

  • More readable: Direct access to metal, mp, and bp instead of metals[i], melting_points[i], etc.