G3 Computing Textbook Chapter 07
G3 Computing Textbook Chapter 07
07 Algorithm Design
274
275
7.1 Introduction to Algorithm Design
7.2 Decomposition
LEARNING OUTCOMES
2.5.2 Solve problems by breaking them down into smaller and more manageable parts (modular
approach).
2.5.3 Solve problems by solving a small version of the problem and gradually extending the
solution to bigger versions of the problem (incremental approach).
Decomposition is a technique of breaking down a complex problem or process into smaller parts such that
each part is more manageable and easier to understand.
Decomposing a problem is used not just for computing, but for any problem that may appear too big or
complex to understand or solve. For instance, to lift and install the 7,000-tonne Marina Bay Sands SkyPark,
the structure was divided into 14 different pieces which were built and assembled separately at ground
level. Breaking down the construction into 14 pieces made each piece small enough to be lifted up, piece
by piece, onto the 57th floor. This would not have been possible if this problem had not been decomposed
beforehand.
276
For instance, let us look at the problem of calculating the mean subject grade (MSG) for seven subjects:
Input Output
If we try to calculate the MSG for the example provided in Table 7.1, we find that the task of converting
rounded percentage scores to grade points is quite independent from the task of summing up the grade
points and dividing the result by 7. This motivates us to use the modular approach.
We can thus decompose the original problem into the following two parts:
Each part is simpler and easier to solve on its own compared to the original problem. The two parts are also
self-contained as the choice of method used to solve part #1 does not affect the choice of method used to
solve part #2.
In code, a modular approach can be implemented by writing each part as a separate function, then
combining inputs and outputs using function calls to get the final output.
277
7.2.2 Incremental Approach
For instance, let us look at the addition problem for whole numbers (positive only):
Input Output
2017 x 2 0 1 7
1965 y 1 9 6 5
3 9 8 2
Table 7.3 Input and output requirements for the addition problem for
whole numbers (positive only)
The addition algorithm in section 4.1.1.1 is based on the premise that it is easy to add single digits. The
reason why this problem is more difficult to solve is that both the inputs and the output can have multiple
digits.
Using the incremental approach, we can gradually extend the solution for single digits to larger versions of
the problem as follows:
278
Part Input Output
2 0 17 x1 2 0 1 7
1 9 65 y1 1 9 6 5
1 2 S1
2 0 1 7 x2 2 0 1 7
1 9 6 5 y2 1 9 6 5
1 2 S1 8 2 S2
2 0 1 7 x3 2 0 1 7
1 9 6 5 y3 1 9 6 5
8 2 S2 9 8 2 S3
Table 7.4 Decomposing the addition problem for whole numbers (positive only)
279
This is how the addition algorithm in section 4.1.1.1 was developed.
In code, an incremental approach is usually implemented as a while or for loop with each iteration
corresponding to one part of the decomposition. The output of each iteration is stored in a variable and
used to calculate the output of the next iteration.
QUICK
EC K 7.2
CH
1. Temperatures in degrees Fahrenheit (°F) can be converted to degrees Celsius (°C) using the following formula:
using the following formula:
Weather can also be classified into different categories based on the temperature T in °C:
• T < 20°C: Cold
• 20°C ≤ T < 30°C: Moderate
• 30°C ≤ T < 35°C: Warm
• T ≥ 35°C: Hot
You are tasked to write a program to output the category of weather (e.g., "Cold", "Moderate", "Warm" or "Hot")
given a temperature in °F as a float.
a) Suggest how decomposition can be used to break this task down into two smaller and simpler tasks.
b) Use your answer in (a) to write the required program. Write each part of the decomposition in a separate
function.
2. You are tasked to write a program that takes in a positive integer n and calculates the following:
1 × 2 × 3 × ... × (n -1) × n
This is the formula for the factorial operation to count the number of ways that n distinct objects can be
arranged. The factorial of n is also written as "n!".
a) The following examples show the relationship between the factorial of a number (e.g., i) and the factorial of
the number incremented (e.g., i+1):
For i = 1: 1! × 2 = (1) × 2 = 2!
For i = 2: 2! × 3 = (1 × 2) × 3 = 3!
For i = 5: 5! × 6 = (1 × ... × 5) × 6 = 6!
For i = 100: 100! × 101 = (1 × ... × 100) × 101 = 101!
By observing a pattern in the above examples or otherwise, complete the following equation with an
expression in terms of i:
i! × ( ) = (i +1)!
b) Use your answer in (a) to fill in line 15 of the following template and complete the required program:
280
QUICK 2
C K 7.
CHE
# Program 7.1: factorial.ipynb
1 # Input
2 while True:
3 n = input('Enter n: ')
4 if n.isdigit():
5 n = int(n)
6 if n > 0:
7 break
8 print('Data validation failed!')
9 print('n must be a positive integer')
10
11 # Process
12 result = 1 # Initialise result to 1! = 1
13 for i in range(1, n): # i starts at 1, ends at n-1
14 # At start of iteration, result is i!
15
16 # At end of iteration, result is (i+1)!
17 # When loop ends, result is n! as required
18
19 # Output
20 print(result)
3. You are tasked to write a program that takes in a message string and outputs the message decorated with an
asterisk (*) between every two characters as well as at the beginning and at the end of the output. If the input
string is empty, then the output should just be a single asterisk.
Input Output
• message: str to decorate • message with an asterisk between every
two characters as well as at the beginning
and at the end of the output.
Table 7.5 Input and output requirements for the asterisk decoration problem
By using the incremental approach to decomposition or otherwise, write the required program.
281
7.3 Generalisation
LEARNING OUTCOMES
2.5.4 Use the technique of solving many small instances of a problem manually to identify the
generic steps that are needed to solve the problem in general.
2.5.5 Recognise when a new problem is similar to an existing problem that has been encountered
before and adapt the corresponding solution to solve the new problem.
Figure 7.4 Generalisation is identifying common Figure 7.5 Factorising x2y + xy2
features from two or more similar items
The same idea can be used to “pull out” common elements or steps from multiple solutions into a more
general solution.
For some computational problems, we can solve simple examples or instances of the problem manually in
the form of test cases. This process helps to ensure we truly understand the problem and the key steps that
a general solution must perform as well.
Note that in general, after generalisation a well-written program will have as little repeated code as possible.
This is known as the "Don't Repeat Yourself" (DRY) principle.
282
For instance, suppose we are required to write a program that accepts a string and extracts digits from the
string by excluding all characters that are not digits.
Input Output
The following are some manually solved test cases for when the input has length 1:
Table 7.8 Test cases for digits extraction problem when input
has length 1
By observing that different steps are taken depending on whether the 1st character is a digit, we obtain a
general solution for when the input has length 1:
283
Next, let's consider when the input has length 2:
Table 7.9 Test cases for digits extraction problem when input has length 2
Figure 7.8 Solution to digits extraction problem when input has length 3
284
By "pulling out" the
common steps from all original = input('Enter string: ')
three solutions, we obtain result = ''
this starting point for a
generic algorithm that ...Missing part...
solves the problem in
general: print(result)
Figure 7.9 Starting point for generic solution to digits extraction problem
This illustrates how manually solving smaller instances of a general problem (e.g., where inputs have
length 1, 2 or 3 only) can lead to a generic solution for the general problem (e.g., where inputs can be of
any length).
U
DID YO
O W ?
N
The program in Figure 7.10 can also be developed using the
K incremental approach to decomposition. When the for loop is at the
i-th character of the input string, result is updated with the correct
output for the first i characters of the input string. In this way, the solution to a small version of the
problem is gradually extended to the solution for larger versions of the problem. Finally, when the
loop ends after iterating through all the characters, result has the correct output for the entire
input string.
285
If we compare this problem to
the digits extraction problem,
we see that the only significant
difference is that the type of 1
2
characters being extracted is 3
changed from digits to letters. 4
This indicates that we can 5
obtain a generic solution to 6
For some problems, more steps are needed to adapt the solution to the existing problem. Suppose we are
required to write a program that accepts a list of non-negative integers and extracts odd numbers from the
list by excluding all numbers that are even:
Input Output
If we compare this problem to the digits extraction problem, we see that both problems involve extracting
items that satisfy some requirement from a sequence of items. However, there are some important
differences:
• For the digits extraction problem, the input and output are strs. For the odd numbers extraction
problem, the input and output are lists.
• For the digits extraction problem, the requirement to check is if the current character is a digit. This
can be done using the isdigit() method. For the odd numbers extraction problem, the requirement
is to check is if the current integer is odd. This can be done by testing if number % 2 == 1 (where
number is the current integer).
These differences require significant changes to the code for receiving input from the user, checking each
item, and including items in the output. However, the core structure of the for loop from line 12 to line 14
of Figure 7.12 remains the same:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
286
QUICK
E C K 7.3
CH
1. A fencing company uses fences that are 1 metre (m) long and must be attached to fenceposts on both sides
of the fence. You are tasked to write a program that takes in the width and length of a rectangular plot of land in
metres (both positive integers) and calculate the smallest number of fenceposts needed to fully enclose the
land with fences.
For instance, if the plot of land is 3 m by 2 m, the smallest number of fenceposts needed is 10. Figure 7.13
illustrates this by showing a top view and numbering the required fenceposts:
a) For each set of inputs below, fill in the expected outputs and description of steps taken to obtain the outputs:
b) By generalising the steps from your answer in (a) or otherwise, write the required program. You may assume
that the input is always valid.
2. You are tasked to write a program that accepts a string and outputs the string with all vowels excluded. For this
question, the vowels are A, E, I, O and U. As an example, if the input is "Hello, world!", the output should be "Hll,
wrld!".
a) Write a function is_vowel() that accepts a string of length 1 and returns a bool for whether the string
contains a vowel. The function should give the correct answer for both uppercase and lowercase vowels.
b) Compare this vowel removal problem to the digits extraction problem. Describe how the solution to the
digits extraction problem in Figure 7.10 can be adapted to solve this vowel removal problem instead.
c) Using your answers in (a) and (b), write the required program.
287
7.4 Common Problems and Solutions
LEARNING OUTCOMES
2.5.1 Explain and use the algorithms for:
• Obtaining the minimum or maximum value(s) in a list without using the min() or max()
functions
• Calculating the sum or average of values in a list without using the sum() function
• Searching for the location(s) of an item in a list or a character in a string without using the
index() or find() methods
• Extracting items from a list or characters from a string based on a given criteria
• Splitting a string into a list based on a given delimiter without using the split() method
For generalisation, it is useful to have a catalogue or “toolbox” of common problems and solutions which
can be adapted to solve similar problems. In this section, we will look at some common problems and their
solutions.
Sometimes we need to find the minimum value in a list of values. Suppose we have a list of heights of a
class of students. Finding the height of the shortest student is thus equivalent to finding the minimum
value in this list.
A common extension to this problem is to find out where this minimum value is located in the list. Suppose
the list of heights is for a class of students and that the heights are arranged in order of registration number.
Finding the registration number of the shortest student in the class is thus equivalent to determining the
index of the minimum value in the list.
Depending on the situation, we may also need to check if a minimum value even exists. Suppose the list
of heights is for students who sign up for a basketball game. If it turns out that no students sign up for the
game, the list of heights would be empty and no minimum value would exist. The solution would need to
be able to handle this case as well.
Input Output
288
A solution to this problem is as follows:
Figure 7.14 Finding the minimum value in a list and its index
The solution starts by checking whether values considered is less than minimum_value (line
has at least one value (line 5). If not, we conclude 9). If so, we update minimum_value and
that values is empty and simply set the outputs to minimum_index with this new value (lines 10
None (lines 13 and 14). and 11). This ensures that minimum_value and
minimum_index are always keeping track of the
Otherwise, we decompose the problem using an minimum value and the location of the minimum
incremental approach. We start by considering this value encountered so far.
small version of the problem: what is the minimum
value if values only has the first value? The solution When the loop ends, we would have considered all
is straightforward: minimum_value is equal to the the values in values and thus can conclude that the
first value in values and minimum_index is equal resulting minimum_value and minimum_index
to 0 (lines 6 and 7). are correct for the entire list.
We then gradually extend this solution by On the other hand, if it is not necessary to find the
considering the rest of the values in values, index of the minimum value, we can simplify the
one-by-one (line 8). The solution is extended program by removing the variables index and
accordingly by checking if the new value being minimum_index completely.
289
Python also provides a built-in min() function that can further simplify the solution if finding the index is
not necessary:
1
2
3
4
5
6
7
8
9
10
11
Figure 7.16 Finding the minimum value of a list using the built-in min() function
By using generalisation, we can easily modify the program in Figure 7.14 so that it finds the maximum value
in a list instead:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Figure 7.17 Finding the maximum value in a list and its index
290
The resulting program is largely the same, except that the greater-than operator (>) is used on line 9
instead of the less-than operator (<), and the output variables are renamed to maximum_value and
maximum_index.
Just as with the previous problem, if it is not necessary to find the index of the maximum value, we can
simplify the program by removing the variables index and maximum_index completely.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Similarly, Python provides a built-in max() function that can further simplify the solution if finding the
index is not necessary:
1
2
3
4
5
6
7
8
9
10
11
Figure 7.19 Finding the maximum value of a list using the built-in max() function
Many problems require us to find the sum of values in a list. Suppose we have a list of profits earned per day
by a store. Calculating the total profit is thus equivalent to finding the sum of values in this list. If the list is
empty, the sum of values is typically considered to be 0.
291
The general problem can be described as follows:
Input Output
Table 7.15 Input and output requirements for the sum problem
1
2
3
4
5
6
7
8
9
10
The solution starts by initialising total to 0, which is the expected sum if values is empty (line 5). We then
iterate though the values in values using a for-in loop and add each value to total (lines 6 to 7). When
the loop finishes, total would thus have the required sum of all the values in values.
Python also provides a built-in sum() function that simplifies the task of calculating the sum of values in
values without the need for a loop:
1
2
3
4
5
6
7
8
Figure 7.21 Finding the sum of values in a list using the built-in sum() function
To avoid accidentally overwriting the built-in sum() function, be careful not to use sum as a variable name
in your own programs.
A common extension to the sum problem is to find the average value in a list. Suppose we have a list of
scores for a class test. Finding the average score for the class is thus equivalent to finding the average value
in this list.
Depending on the situation, we may also need to check if an average value even exists. Suppose the list of
scores is for an optional test. If it turns out that no students choose to take the test, the list of scores would
be empty and no average value would exist.
292
The general problem to the situation above can be described as follows:
Input Output
Table 7.16 Input and output requirements for the average problem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
The solution starts by checking whether values has at least one value (line 5). If not, we conclude that
values is empty and simply set the output to None (line 11).
Otherwise, we calculate the sum of the values in values using a for-in loop (lines 7 to 8) and divide this
sum by the length of values to obtain the required average (line 9).
Just as with the previous problem, we can also use the built-in sum() function instead of a loop. This
version is typically preferred as it is simpler:
1
2
3
4
5
6
7
8
9
10
11
12
293
7.4.3 Finding the Location of a Value
As we have learnt in Chapter 4, the in operator can tell us whether a value is in a list, but it does not tell
us where the value is located. Hence, the in operator is insufficient for problems that require us to find the
index of a value in a list. Suppose we have a list of students’ names such that the index of each value is
the corresponding student’s registration number. Finding the registration number of a particular student is
thus equivalent to searching for the student’s name in this list and retrieving its index.
Depending on the situation, the search may not be able to find the value. Suppose the name that we input
for searching is misspelled. The program would not be able to find this name in the list and must be able
to handle this situation as well.
Input Output
Table 7.17 Input and output requirements for the searching problem
1
2
3
4
5
6
7
8
9
10
11
12
13
The solution first initialises the output search_index to None (line 6). This ensures that if no match is
found or if values is empty, search_index correctly remains as None.
Using an incremental approach, we then check each value in the list in order (line 7) to see if a match can
be found (line 8). Once a match is found, we set search_index as the index of the matching value and stop
the search immediately using a break command (lines 9 to 10).
294
U
DID YO
N O W ?
K
This algorithm is also known as a "linear search" or "sequential search" as it
goes through each item of the list in sequential order until a match is found.
Step 1: 1 9 6 5 2 0 4 8
Step 2: 1 9 6 5 2 0 4 8
Step 3: 1 9 6 5 2 0 4 8
Step 4: 1 9 6 5 2 0 4 8
Step 5: 1 9 6 5 2 0 4 8
Step 6: 1 9 6 5 2 0 4 8
Step 7: 1 9 6 5 2 0 4 8
Besides linear search, there are other search algorithms that typically require items to be organised in
a special manner to speed up the search. For instance, if the items in the list are sorted beforehand, an
efficient "binary search" can be performed where half of the remaining options for the correct location
can be eliminated with each step.
Step 1: 0 1 2 4 5 6 8 9
Step 2: 0 1 2 4 5 6 8 9
Step 3: 0 1 2 4 5 6 8 9
Figure 7.26 Example of binary search for 4 in a sorted list
Note that if we wish to search for the location of a substring in a string instead of the location of an item in
a list, we can alternatively use str's built-in find() method instead of writing a for loop.
U
DID YO
KNOW?
Besides the find() method of strs, Python lists and strs also have a built-
in index() method to search for an item or substring and return its index.
However, be aware that unlike find() which returns a special value of -1,
index() will generate an error which needs to be handled if the search item or
substring cannot be found.
295
7.4.4 Extracting Values Based on Given Criteria
In section 7.3, we have already seen some examples of problems that require extracting subsets of
characters or items from a str or list.
If the required subset is based solely on index, we can use slicing. For instance, my_string[4:6] extracts
the 5th and 6th characters from a string named my_string.
However, the examples in section 7.3 required more complex requirements for deciding which characters
or items to extract, such as:
• Extracting only the digits from a string
• Extracting only the alphabetical letters from a string
• Extracting only the odd numbers from a list of non-negative integers
Input Output
Table 7.18 Input and output requirements for the str extraction problem
A solution for this problem, using the isdigit() method for test(), is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
296
The solution starts by initialising the output variable extract to an empty string (line 8). Using an
incremental approach, we then consider the characters of the original string, one by one and in order (line
9), to see if each character meets our requirements for extraction (line 10). Each character that meets our
requirements is appended to our output (line 11).
When the loop ends, we would have considered all the characters in the original string and thus can
conclude that extract has all the characters that meet our requirements.
Input Output
Table 7.19 Input and output requirements for the list extraction problem
A solution for this problem, using a list of integers and a test() function that checks if an integer is odd,
is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
The solution starts by initialising the output variable extract to an empty list (line 8). Using an
incremental approach, we then consider the items of the original list, one by one and in order (line 9), to
see if each item meets our requirements for extraction (line 10). Each item that meets our requirements is
appended to our output (line 11).
When the loop ends, we would have considered all the items in the original list and thus can conclude
that extract has all the items that meet our requirements.
297
U
DID YO
N O W ?
K
Besides using a for loop, Python offers two alternative ways to
extract items from a list based on a given criteria.
First, Python has a filter() function that accepts a function and a list. Its output can be
converted to a list of only the items where the function returns True. The following example
demonstrates how to extract odd numbers from a list using filter():
1
2
3
4
5
Second, Python has a unique and compact "list comprehension" syntax for creating lists
where a condition can be specified before items are included in the list. The following example
demonstrates how to perform the same task of extracting odd numbers from a list using a list
comprehension:
1
2
3
Figure 7.30 Extracting required items from a list using a list comprehension
These techniques are generally shorter to write but can be more complex to understand.
298
We can specify this problem as follows:
U
DID YO
Input Output
N O W ?
• s: a str • A list of strs such that: K
• delimiter: a non- • delimiter is not a Python has a csv module
empty str substring of any strs
that offers built-in support
in the list; and
for reading and writing CSV
• s is recovered by
files. However, use of this
inserting delimiter
between the strs in module is not covered in
the list this textbook.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
This solution starts by initialising the output variable pieces to an empty list (line 6). It also initialises a
variable named current which tracks the start index of the next str that will be added to the output (i.e.,
the "current piece"). We observe that the first str always starts at index 0 even for the boundary condition
when delimiter appears at the start of s, so we initialise current to 0.
The solution then enters a continuous loop of looking for the next appearance of delimiter from the start
index of the current piece onwards (lines 8 to 9).
If delimiter is not found (line 11), then the current piece must also be the last piece. We extract the last
piece by slicing s from current to the end of the string, add it to the output and break out of the loop (lines
12 to 14).
299
Otherwise, the current piece must end at delimiter_start, so we extract it by slicing s from current to
delimiter_start and add it to the output (lines 16 to 17). We then advance current to the end of the
delimiter where the next piece will start (line 18) before the loop repeats.
Note that if delimiter appears at the start of s, end of s or multiple times consecutively in s, then the
resulting output may include empty strings. This is correct based on the specification of our problem in
Table 7.20:
Enter s: a///b///c
Enter delimiter: /
For the special case of space delimiters, if we wish to split a string such that empty strings are omitted, we
can alternatively use str's built-in split() method without any arguments:
print('a b c'.split())
However, be aware that if we specify a delimiter explicitly using an argument, then the built-in split()
method behaves identically to our version in Figure 7.32 such that empty strings may be included:
Overall, str's built-in split() method provides an alternative way to solve the problem in Table 7.20:
1
2
3
4
5
6
7
8
9
Figure 7.35 Splitting a string based on a given delimiter using the split() method
300
QUICK
E C K 7.4
CH
1. Write a program that lets the user input a list of ints by asking for each item of the list in order. Receiving
an empty input from the user would indicate the end of the list. The program would then output the smallest
int in the list, followed by a space, followed by the second smallest int in the list. However, if the list has
fewer than two items, it should output the word “None” instead.
You are not allowed to use min() or any built-in sorting functions.
Assume that the input data will always be valid and none of the ints are repeated.
Two test cases for how the program should behave with different inputs are as follows:
-20 19
None
2. Write a program that lets the user input a list of floats by first asking for the number of items in the list,
then asking for each item of the list in order. The program would then output the average of only the positive
floats in the list, rounded to two decimal places. However, if the list has no positive floats, it should
output the word “None” instead.
Two test cases for how the program should behave with different inputs are as follows:
Enter length: 4
74.92
301
QUICK
E C K 7.4
CH
Enter length: 0
None
3. Modify the program in Figure 7.31 such that empty strings are not included in the output. A sample run
demonstrating the new required behaviour is as follows:
Enter s: a///b///c
Enter delimiter: /
W
REVIE
ES T I ON
QU
1. The number of visitors to a park per day is provided as comma-separated values of non-negative integers such
that the number of visitors on day 1 is the first value, the number of visitors on day 2 is the second value, and
so on.
You are tasked to write a program to accept the comma-separated values and identify the day when there is the
largest absolute change in number of visitors from the previous day. It is guaranteed that the input is valid,
there is at least two values in the input and that there is an unambiguous answer (i.e., no two days will share
the same largest absolute change in number of visitors).
302
W
REVIE N
S TI O
QUE
2. The following program uses a dictionary to count the number of times each character appears in a string:
a) Output the most frequent character in the input string. It is guaranteed that the input string is not empty
and no two characters share the highest frequency.
b) Output whether every character in the string is unique (i.e., appears only once in the string). It is guaranteed
that the input string is not empty.
3. The non-negative integer number of items sold in a store per day over multiple weeks is provided as comma-
separated values via a text file named sales.txt. Each line of the file represents a week and the seven comma-
separated values of each line are the number of items sold for each day of that week from Sunday to Saturday.
Write a program that reads in the data from sales.txt and outputs the day of week (i.e., "Sunday", "Monday",
"Tuesday", etc.) with the highest total number of items sold. It is guaranteed that the input is valid, there is
at least one week of data, every line has complete data for all seven days of the week and that there is an
unambiguous answer (i.e., no two days will share the same largest number of items sold).
Table 7.22 Test cases for largest total items sold problem
303
W
REVIE
ES T I ON
QU
4. The names of students who have signed up for basketball and football at a sports festival are stored in separate
text files named basketball.txt and football.txt respectively with each student’s name on a separate
line. Write a program to count the number of students who signed up for both basketball and football. It is
guaranteed that all students have unique names and there are no repeated names in each file.
5. The following is an example of a 5x5 "text image" made using text characters:
*****
@@@?-
@@?--
@?---
*****
After the text image is rotated 90° clockwise, it looks like this:
*@@@*
*?@@*
*-?@*
*--?*
*---*
You are tasked to write a program that loads a text image from a file named image.txt and outputs the text
image rotated 90° clockwise.
304
W
REVIE
ES T I ON
QU
The first line of image.txt will be a positive integer equal to the width and height of the text image. For instance,
the following is an example of image.txt:
13
---*-----*---
--*-*---*-*--
-*---***---*-
*-----------*
*--++---++--*
*-----------*
*---X---X---*
-*---------*-
--*-------*--
---*-----*---
----*@@@*----
-----*@*-----
------*------
6. Write a join() function that accepts a list of strs (i.e., pieces) and a delimiter, then "reverses" the split
operation by returning a str where delimiter is inserted between the strs in the list. You are not allowed to
use str's built-in join() method.
7. Write a program that accepts two strs, message and borders. The output of the program is message enclosed
by nested decorative boxes made up of the characters in borders. The nested boxes must follow the characters
in borders using an outside-in order.
305
W
REVIE
ES TI ON
QU
→ Input Expected Output →
• message: 'Hello, world!' *****************
• borders: '*$' *$$$$$$$$$$$$$$$*
*$Hello, world!$*
*$$$$$$$$$$$$$$$*
*****************
• message: ' C O M P U T I N G ' 1111111111111111111111111
• borders: '123' 1222222222222222222222221
1233333333333333333333321
123 C O M P U T I N G 321
1233333333333333333333321
1222222222222222222222221
1111111111111111111111111
8. You are tasked to write a program that converts integers from 0 (inclusive) to 999,999 (inclusive) into English
words.
306
W
REVIE
ES T I ON
QU
a) By examining any repeated steps needed to solve the problem for an input of 999,999, suggest a reusable
function that may be written to solve a smaller version of this problem and would be useful for solving the
full problem.
ANSWER
def classify_temp(t):
if t < 20:
return "Cold"
elif t < 30:
return "Moderate"
elif t < 35:
return "Warm"
else:
return "Hot"
2. a) i! × (i +1) = (i +1)!
b)
# Program: factorial.ipynb
1 # Input
2 while True:
3 n = input('Enter n: ')
4 if n.isdigit():
5 n = int(n)
6 if n > 0:
7 break
8 print('Data validation failed!')
9 print('n must be a positive integer')
10
11 # Process
12 result = 1 # Initialise result to 1! = 1
13 for i in range(1, n): # i starts at 1, ends at n-1
14 # At start of iteration, result is i!
15 result = result * (i + 1)
16 # At end of iteration, result is (i+1)!
17 # When loop ends, result is n! as required
18
19 # Output
20 print(result)
307
ANSWER
print(result)
308
ANSWER
(Note: There are many possible steps that can be taken to obtain the correct expected output for each test case.)
309
ANSWER
b) By generalising the steps from (a), a general formula for the total number of fenceposts needed is:
b) The solution to the digits extraction problem can be adapted to solve the vowel removal problem by
changing the condition for including character c in the output. The condition could be changed from
checking if c is a digit with c.isdigit() to checking if c is not a vowel with not is_vowel(c).
310
ANSWER
2. A possible answer is as follows:
# Program: positive_average.ipynb
1 # Input
2 length = int(input("Enter length: "))
3 values = []
4 for i in range(length):
5 value = float(input("Enter item: "))
6 values += [value]
7
8 # Process
9 average = None
10 sum_values = 0
11 num_positive = 0
12 for value in values:
13 if value > 0:
14 sum_values += value
15 num_positive += 1
16 if num_positive > 0:
17 average = round(sum_values / num_positive, 2)
18
19 # Output
20 print(average)
311
ANSWER
2. a) A possible answer is as follows:
# Program: most_frequent_character.ipynb
1 # Input
2 s = input('Enter string: ')
3
4 # Process
5 counts = {}
6 for c in s:
7 if c not in counts:
8 counts[c] = 0
9 counts[c] += 1
10
11 most_frequent = None
12 for c in counts:
13 if most_frequent == None:
14 most_frequent = c
15 elif counts[c] > counts[most_frequent]:
16 most_frequent = c
17
18 # Output
19 print(most_frequent)
312
ANSWER
3. A possible answer is as follows:
totals = [0] * 7
with open('sales.txt') as f:
for line in f:
index = 0
for day in line.split(','):
totals[index] += int(day)
index += 1
count = 0
for name in basketball:
if name in football:
count += 1
print(count)
output = [message]
for border in borders[::-1]:
output = decorate(output, border)
for line in output:
print(line)
313
ANSWER
An alternative answer that does not use a list of lines is as follows:
message = input('Enter message: ')
borders = input('Enter borders: ')
for i in range(len(borders)):
left = borders[:i]
middle = borders[i] * (len(message) + 2 * (len(borders) - i))
right = left[::-1]
print(left + middle + right)
8. a) Either:
• Based on the repeated steps needed to generate "ninety-nine", a reusable function could be written to solve the
smaller problem of converting integers from 0 to 99 (inclusive) into English words.
• Based on the repeated steps needed to generate "nine hundred and ninety-nine", a reusable function could be
written to solve the smaller problem of converting integers from 0 to 999 (inclusive) into English words.
def convert_belowhundred(number):
""" Convert numbers from 0 to 99 inclusive. """
# Numbers below 20 inclusive are special.
if number < 20:
return belowtwenty[number]
# Then add hyphen and word for the ones place if needed.
ones = number % 10
if ones == 0:
return tens_words
return tens_words + '-' + belowtwenty[number % 10]
def convert_belowthousand(number):
""" Convert numbers from 0 to 999 inclusive. """
# Use convert_belowhundred() if number is below 100.
if number < 100:
return convert_belowhundred(number)
# Then add "and" and words for the tens and ones place if needed.
tens_and_ones = number % 100
if tens_and_ones == 0:
return hundreds_words
return (hundreds_words + ' and ' +
convert_belowhundred(tens_and_ones))
def convert(number):
""" Convert numbers from 0 to 999,999 inclusive. """
# Use convert_belowthousand() if number is below 1000.
if number < 1000:
return convert_belowthousand(number)
314
ANSWER
# Then add words for the hundreds, tens and ones place if needed.
hundreds_tens_and_ones = number % 1000
if hundreds_tens_and_ones == 0:
return thousands_words
# Special rule: "and" needed if hundreds_tens_and_ones < 100
if hundreds_tens_and_ones < 100:
thousands_words += ' and'
return (thousands_words + ' ' +
convert_belowthousand(hundreds_tens_and_ones))
315