Sharing notes from my ongoing learning journey — what I build, break and understand along the way.
Python Practice Exercises – Part 6: Fractions, GCD, and Functional Programming
Python Practice Exercises – Part 6
Try to solve each exercise on your own first.
After the exercise list, scroll down to the “Solutions” section to compare your approach.
Exercises
Exercise 1 – Digit-Cancelling Fractions
Normally, you may not just “cancel digits” in a fraction.
For example, 18/12 is obviously not the same as 8/2 (if you just remove the 1).
However, there are rare two-digit fractions where this wrong-looking “digit cancelling” coincidentally gives the correct result.
For example, 65/26 has the same value as 5/2 if you cancel the digit 6 from numerator and denominator.
Write a program that finds all pairs of two-digit numbers (numerator and denominator) where this kind of digit cancelling works.
Requirements:
- Only use two-digit numbers (10–99).
- Only consider values less than 1 (numerator < denominator).
- Exclude trivial cases such as fractions with zeros like 10/70 or obviously reducible ones that just cancel a trailing zero.
Exercise 2 – Greatest Common Divisor (GCD) – Recursive
Write a recursive function that computes the greatest common divisor (GCD) of two numbers, using the Euclidean algorithm:
- Divide the larger number by the smaller one.
- If the remainder is 0, the smaller number is the GCD.
- Otherwise, repeat the process with the smaller number and the remainder.
Example:
- 80 / 65 → remainder 15 → continue with (65, 15)
- 65 / 15 → remainder 5 → continue with (15, 5)
- 15 / 5 → remainder 0 → GCD is 5
Exercise 3 – Character Frequencies
Write a function char_frequencies() that, for a given string, returns a dictionary mapping each character to the number of times it appears.
Example:
print(char_frequencies('Strawberry'))
# Example output (order may vary):
# {'S': 1, 't': 1, 'r': 3, 'a': 1, 'w': 1, 'b': 1, 'e': 1, 'y': 1}
Exercise 4 – Straight-Line Distance (Luftlinie)
Write a function that computes the distance between two points in the plane.
- A point is given as
(x, y), for exampleP1 = (x1, y1),P2 = (x2, y2). - Use it to compute distances like:
Verification examples:
- P1 = (-4, 2); P2 = (-1, 6) → distance = 5
- P1 = (-1, 6); P2 = (4, 18) → distance = 13
Example with Swiss coordinates (CH1903):
- Zell = (704.4, 256.2)
- Neuburg = (693.3, 261.4)
They should be about 12.26 km apart.
Exercise 5 – Steganography
Steganography is the technique of hiding secret information inside another text.
Write a function hide(text, n=1) that obfuscates a plaintext string text as follows:
- Convert the string to uppercase.
- After each letter, insert
nrandom uppercase letters. - Spaces should remain spaces.
nis optional and defaults to 1.
Example calls (your random output will differ):
print(hide('Meet at noon'))
# e.g.: MAFEEZTB AT QFXNTOJONZ
print(hide('Meet at noon', 2))
# e.g.: MABXEEJTTK AT HQLXOOFONZQ
Exercise 6 – Extract Vowels
From a given string like "Magermilchjoghurt", extract all vowels and join them into a new string.
Solve this in two ways:
- Using a classic loop.
- Using a higher-order function (e.g.
filter()withlambda).
Exercise 7 – Bookstore Orders with map() and lambda
You have the following list of orders:
orders = [
["34587", "Learning Python, Mark Lutz", 4, 40.95],
["98762", "Programming Python, Mark Lutz", 5, 56.80],
["77226", "Head First Python, Paul Barry", 3, 32.95]
]
Each sublist has:[order_id, title_and_author, quantity, unit_price]
Write code using map() and lambda to produce a list of 2-tuples:
(order_id, total_price)
Where:
total_price = quantity * unit_price- If this product is less than 100, add a surcharge of 10.
So for small orders, total price = product + 10.
You are allowed to nest map() calls if you want.
Exercise 8 – Maximum Word Length
Given the string:
s = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor"
s += " invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et"
s += " accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata"
s += " sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing"
s += " elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,"
s += " sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd"
s += " gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
Determine the maximum word length (number of letters of the longest word).
You may ignore punctuation marks when counting letters.
Exercise 9 – Sum of Numbers from 1 to 1000
Find four different ways to compute the sum of the numbers from 1 to 1000.
For example:
- Using a
forloop - Using a
whileloop - Using
reduce()withlambda - Using
sum()with a comprehension orrange()
Exercise 10 – Multiples of Seven
Find four different ways to build a list of all multiples of seven that are less than 100:
The final list should be:
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]
Do this in four different ways, for example:
- Using
range()with three parameters - Using a list comprehension
- Using
filter()andlambda - Using
map()andlambda
Solutions and Explanations
Solution 1 – Digit-Cancelling Fractions
def digit_cancelling_fractions():
results = []
for num in range(10, 100):
for den in range(10, 100):
if num >= den:
continue # we only want fractions < 1
# Exclude anything with zeros (trivial or invalid digit cancelling)
if num % 10 == 0 or den % 10 == 0:
continue
num_str = str(num)
den_str = str(den)
# Look for a common digit to "cancel"
for d in num_str:
if d in den_str:
# Build "simplified" numerator and denominator
new_num_str = num_str.replace(d, "", 1)
new_den_str = den_str.replace(d, "", 1)
# Skip if this removes all digits
if not new_num_str or not new_den_str:
continue
new_num = int(new_num_str)
new_den = int(new_den_str)
if new_den == 0:
continue
original_value = num / den
cancelled_value = new_num / new_den
if abs(original_value - cancelled_value) < 1e-9:
results.append((num, den, new_num, new_den))
return results
fractions = digit_cancelling_fractions()
for num, den, new_num, new_den in fractions:
print(f"{num}/{den} == {new_num}/{new_den}")
Explanation:
We try all two-digit numerator/denominator pairs, avoid zeros (to exclude trivial 30/50 cases), and check if cancelling a common digit gives the same numeric value.
Solution 2 – Recursive GCD (Euclidean Algorithm)
def gcd(a, b):
if b == 0:
return abs(a)
return gcd(b, a % b)
print(gcd(80, 65)) # 5
print(gcd(15, 5)) # 5
print(gcd(42, 56)) # 14
Explanation:
The Euclidean algorithm repeatedly replaces the pair (a, b) with (b, a % b) until the remainder is 0. The last non-zero value is the GCD
Solution 3 – Character Frequencies
def char_frequencies(text):
freq = {}
for ch in text:
if ch in freq:
freq[ch] += 1
else:
freq[ch] = 1
return freq
print(char_frequencies("Erdbeere"))
Explanation:
We maintain a dictionary where each key is a character, and the value is the count. For every character, we increment its count.
Solution 4 – Distance Between Two Points
import math
def distance(p1, p2):
x1, y1 = p1
x2, y2 = p2
return math.hypot(x2 - x1, y2 - y1)
print(distance((-4, 2), (-1, 6))) # 5.0
print(distance((-1, 6), (4, 18))) # 13.0
zell = (704.4, 256.2)
neuburg = (693.3, 261.4)
print(distance(zell, neuburg)) # ~12.26
Explanation:
The distance formula is:√((x2 - x1)² + (y2 - y1)²)math.hypot(dx, dy) computes exactly this.
Solution 5 – Steganography
import random
import string
def hide(text, n=1):
text = text.upper()
result_parts = []
for ch in text:
if ch == " ":
result_parts.append(" ")
else:
random_letters = "".join(random.choice(string.ascii_uppercase) for _ in range(n))
result_parts.append(ch + random_letters)
return "".join(result_parts)
print(hide("Um acht an der Uhr"))
print(hide("Um acht an der Uhr", 2))
Explanation:
- Convert to uppercase.
- For each letter, add
nrandom uppercase letters. - Keep spaces as spaces to preserve word boundaries.
Solution 6 – Extract Vowels
vowels = "aeiouAEIOU"
# Classic loop
def extract_vowels_loop(text):
result = ""
for ch in text:
if ch in vowels:
result += ch
return result
# Higher-order function (filter + lambda)
def extract_vowels_filter(text):
return "".join(filter(lambda ch: ch in vowels, text))
print(extract_vowels_loop("Magermilchjoghurt"))
print(extract_vowels_filter("Magermilchjoghurt"))
Explanation:
Both functions return the string of vowels only.
The second one uses filter() with a lambda function as requested.
Solution 7 – Bookstore Orders with map() and lambda
orders = [
["34587", "Learning Python, Mark Lutz", 4, 40.95],
["98762", "Programming Python, Mark Lutz", 5, 56.80],
["77226", "Head First Python, Paul Barry", 3, 32.95]
]
def compute_totals(orders_list):
return list(
map(
lambda order: (
order[0],
order[2] * order[3] if order[2] * order[3] >= 100
else order[2] * order[3] + 10
),
orders_list
)
)
print(compute_totals(orders))
Explanation:
- For each order, calculate
quantity * unit_price. - If it’s less than 100, add 10.
- Return
(order_id, total_price)as a tuple in a list.
Solution 8 – Maximum Word Length
import string
def max_word_length(text):
words = text.split()
max_len = 0
for w in words:
cleaned = w.strip(string.punctuation)
if len(cleaned) > max_len:
max_len = len(cleaned)
return max_len
print(max_word_length(s))
Explanation:
We split into words, remove punctuation from the start and end of each word, and track the maximum length.
Solution 9 – Sum of Numbers from 1 to 1000
from functools import reduce
# 1. For loop
def sum_for():
total = 0
for i in range(1, 1001):
total += i
return total
# 2. While loop
def sum_while():
total = 0
i = 1
while i <= 1000:
total += i
i += 1
return total
# 3. reduce + lambda
def sum_reduce():
return reduce(lambda x, y: x + y, range(1, 1001))
# 4. sum() + range
def sum_builtin():
return sum(range(1, 1001))
print(sum_for())
print(sum_while())
print(sum_reduce())
print(sum_builtin())
Explanation:
All four methods produce the same result (500500) but with different styles: imperative loops, functional reduce, and the built-in sum().
Solution 10 – Multiples of Seven
# 1. range() with step
multiples1 = list(range(7, 100, 7))
# 2. List comprehension
multiples2 = [x for x in range(1, 100) if x % 7 == 0]
# 3. filter() + lambda
multiples3 = list(filter(lambda x: x % 7 == 0, range(1, 100)))
# 4. map() + lambda
multiples4 = list(map(lambda k: 7 * k, range(1, 100 // 7 + 1)))
print(multiples1)
print(multiples2)
print(multiples3)
print(multiples4)
Explanation:
Each approach generates the same list of multiples in a different style (step-based range, comprehension, filter, and map).
