Week 5 Exercises — For-Loop Practice

exercises
python
for-loops
comprehensions

Practice exercises for week 5 (Lecture 5C, “For Loop Practice”), following on from 2025-08-25-for-loops and 2025-08-25-comprehensions. See python-for-loops and python-comprehensions for the reference material needed to solve these.

On the HTML site, fill in each blank with your answer, then click Run Code to check it. In the PDF, the Working callout is shown as a static answer key instead (interactive checking needs a browser).

Q1 — Capitalize a string

def capitalize(cs: str) -> str:
    """ Capitalize every alphabet letter of a string.
    >>> capitalize("boom goes the dynamite!")
    'BOOM GOES THE DYNAMITE!'
    >>> capitalize("123")
    '123'
    """
acc += chr(ord('A') + ord(c) - ord('a'))

Shifting a lower-case letter up to its capital by the fixed gap between 'A' and 'a' in the character encoding.

Q2 — Matrix transpose

def transpose(xss: list[list[int]]) -> list[list[int]]:
    """ Return the transpose of xss (rows and columns swapped).
    Precondition: xss is square, i.e. len(xss) == len(xss[0]) == ...
    >>> transpose([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
    >>> transpose([[1]])
    [[1]]
    """
row = [xs[k] for xs in xss]

Row k of the transpose is column k of the original — the k-th element of every row xs in xss.

Q3 — Caesar cipher

A Caesar cipher shifts each letter a fixed number of places down the alphabet (wrapping around) to encrypt; shifting by the negative amount decrypts it again.

def caesar_cipher(cs: str, shift: int) -> str:
    """ Return a string where each character of <cs> has been shifted
    by <shift> according to the Caesar cipher.
    >>> caesar_cipher("HELLO", 3)
    'KHOOR'
    >>> caesar_cipher("KHOOR", -3)
    'HELLO'
    >>> caesar_cipher("abc xyz", 2)
    'cde zab'
    >>> caesar_cipher("cde zab", -2)
    'abc xyz'
    """

This resolves the Caesar cipher exercise posed (and left unsolved) back in 2025-08-18-non-primitive-data — same idea, a single shift parameter instead of separate encrypt/decrypt functions.

acc += chr((ord(c) - ord('a') + shift) % 26 + ord('a'))

% 26 wraps the shift around the alphabet in both directions (including for negative shifts, since Python’s % always returns a non-negative result for a positive divisor).

Q4 — Combine two dictionaries

def combine(d1: dict[int, list[int]], d2: dict[int, list[int]]) -> dict[int, int]:
    """ Return the dictionary where each key is a key that is in both
    d1 and d2. The value for each key is the sum of all the integers
    associated with that key in d1 and d2.
    >>> combine({1: [2], 4: [5, 6]}, {4: [8]})
    {4: 19}
    """
acc[key] = sum(d1[key]) + sum(d2[key])

Q5 — Reverse lookup

def reverse_lookup(d: dict, item) -> list:
    """ Returns all keys of <d> such that d[key] == item.
    Precondition: the items of <d> are immutable.
    >>> reverse_lookup({1: 'bluey', 19: 'chilli', -31: 'bluey'}, 'bluey')
    [1, -31]
    >>> reverse_lookup({1: 'bluey', 19: 'chilli', -31: 'bluey'}, 'muffin')
    []
    """
if d[k] == item:

Q6 — Invert a dictionary

def invert(d: dict) -> dict:
    """ Return the inverted version of d (values become keys, mapping
    to a list of the original keys that shared that value).
    >>> invert({1: 10, 2: 10})
    {10: [1, 2]}
    """
acc[val] = [key]