0% found this document useful (0 votes)
19 views42 pages

G3 Computing Textbook Chapter 07

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views42 pages

G3 Computing Textbook Chapter 07

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 42

CHAPTER

07 Algorithm Design

274
275
7.1 Introduction to Algorithm Design

A programming language such as


Python is just a tool that allows us to
ER MS
communicate with computers. Simply
knowing a programming language is not
KEY T
enough to solve complex problems; it Computational thinking
is also necessary to learn strategies for A process of formulating problems so their solutions
designing the step-by-step instructions or can be represented as algorithms
algorithm for solving specific problems.
Decomposition
Algorithm design typically requires the Breaking down a complex problem or process into
use of computational thinking skills smaller and more manageable parts
to formulate or express problems in a
way such that their solutions can be
performed by a computer. Two such skills
are decomposition and generalisation.

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.

7.2.1 Modular Approach

One approach to decomposition is to break the


problem down into smaller parts that are relatively
self-contained such that how one part is solved
does not depend on how other parts are solved. The
different parts are typically combined by using the
output of one part as the input to another part. This is
the modular approach to decomposition.
Figure 7.1 Breaking a problem down into smaller
parts that are different from each other

276
For instance, let us look at the problem of calculating the mean subject grade (MSG) for seven subjects:

Input Output

• Score: rounded percentage • MSG for the seven subjects,


score for subject; must be a rounded to two decimal
whole number between 0 places
and 100 inclusive (provided
seven times, once for each
subject)

Table 7.1 Input and output requirements for the problem of


calculating the MSG for seven subjects

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:

Part Input Output

#1 • Score: rounded percentage • Grade points:


score for subject; must be a corresponding grade
whole number between 0 and points for subject (output
100 inclusive (provided seven seven times, once for each
times, once for each subject) subject)

#2 • Grade points: grade points • MSG for the seven subjects,


for subject; must be a whole rounded to two decimal
number between 1 and 9 places
inclusive (provided seven
times, once for each subject)

Table 7.2 Input and output requirements for the problem of


calculating the MSG for seven subjects

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

Another approach to decomposition is to solve a


small version of the problem and gradually extend
the solution to larger versions of the problem. For
problems that work with this approach, typically the
correct output is easy to calculate when the input is
at its lower limit (e.g., an empty list). This output can
then be used to calculate the correct output when the
input in incremented (e.g., increasing the list’s length
by 1), which in turn can be used to calculate the correct
output when the input is incremented again, and so on.
This is the incremental approach to decomposition. Figure 7.2 Solving a small version of the problem and
gradually extending the solution to larger versions

For instance, let us look at the addition problem for whole numbers (positive only):

Input Output

• x: a positive whole number • The sum of x and y


• y: a positive whole number Example:
Example:

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

#1 • x1: the last digit of x • s1: The sum of x1 and y1


• y1: the last digit of y Example:
Example:

2 0 17 x1 2 0 1 7
1 9 65 y1 1 9 6 5
1 2 S1

#2 • x2: the last two digits of x • s2: The sum of x2 and y2


• y2: the last two digits of y Example:
• s1: The result of solving part #1
Example:

2 0 1 7 x2 2 0 1 7
1 9 6 5 y2 1 9 6 5
1 2 S1 8 2 S2

#3 • x3: the last three digits of x • s3: The sum of x3 and y3

• y3: the last three digits of y Example:

• s2: The result of solving part #2


Example:

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

...and so on... ...and so on... ...and so on...

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:

Temperature in °C = (Temperature in °F - 32) × 5/9

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)

Figure 7.3 Template for program to calculate the factorial of a number

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.

• If message is empty, then the output


should just be a single asterisk.

Table 7.5 Input and output requirements for the asterisk decoration problem

The following are some test cases to illustrate the problem:

→ Input Expected Output →


• message: "" *
• message: "Hello" *H*e*l*l*o*
• message: "* *" *** ***

Table 7.6 Test cases for 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.

T E R MS Generalisation is the technique of identifying common features from


K E Y two or more similar items. These common features are often used to
form with a single, more general item that can be used to replace or
Generalisation represent the original items.
Identifying common
features from two or In most cases, generalisation can be accomplished by following a
more similar items process similar to how factorisation is done in algebra. For example, in
the expression x2y + xy2, we identify x and y as common factors across
its terms. The largest common factor xy, can then be “pulled out” so
that only the factors that are different remain.

x2y + xy2 = xxy + xyy


= x(xy) + (xy)y
=(xy)(x+y)

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.

7.3.1 Solving Small Instances of the Problem Manually

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.

To perform generalisation, we examine the steps taken to identify:


• common steps that can be "pulled out" as the starting point for a generic algorithm that solves the
problem in general;
• repeated steps that can be "pulled out" as reusable functions; and
• repeated steps that can be simplified or shortened using while or for loops

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

• original: str to extract • extracted digits (in the same


characters from order and quantity that they
appear in original)

Table 7.7 Input and output requirements for the digits


extraction problem

The following are some manually solved test cases for when the input has length 1:

→ Input Expected Output → Description of Steps

• original: "A" (blank output) • 1st character is not a digit,


so it is excluded
A
• Output is blank since no
characters were included

• original: "1" 1 • 1st character is a digit, so it


is included 1
• Output is 1st character

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:

Figure 7.6 Solution to digits extraction problem when input


has length 1

283
Next, let's consider when the input has length 2:

→ Input Expected Output → Description of Steps

• original: "hi" (blank output) • 1st character is not a digit,


so it is excluded h
• 2nd character is not a digit,
so it is excluded
• Output is blank since no h i
characters were included

• original: "2B" 2 • 1st character is a digit,


so it is included 2
• 2nd character is not a digit,
so it is excluded
• Output is 1st character
2 B

• original: "42" 42 • 1st character is a digit,


so it is included
4
• 2nd character is a digit,
so it is included
• Output is 1st and 2nd
characters 4 2

Table 7.9 Test cases for digits extraction problem when input has length 2

The steps for the 1st character


are the same, but subsequently
different steps are taken
depending on whether the 2nd
character is a digit. Converting
this to code, we obtain a
general solution for when the
input has length 2:
Figure 7.7 Solution to digits extraction problem when input has length 2

Similarly, we can obtain a


general solution when the
input has length 3:

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

To complete the program,


observe that the missing
part corresponds to
1
checking if each character
2
of original is a digit, and
3
if so, including it in the
4
output. Instead of checking
5
each character manually,
6
these repeated steps can be
shortened and simplified
using a for loop to obtain Figure 7.10 Generic solution to digits extraction problem
the following generic
solution:

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.

7.3.2 Adapting Solutions to Similar Problems

Sometimes, what appears to be a new


Input Output problem is actually similar to a known
existing problem. This usually indicates
• original: str to • extracted letters (in that it is possible to adapt an existing
extract characters the same order and solution to solve the problem.
from quantity that they
appear in original) For instance, suppose we are required to
write a program that accepts a string and
extracts alphabetical letters from the
Table 7.10 Input and output requirements for the letters string by excluding all characters that
extraction problem
are not letters.

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

this problem by just changing


the method call on line 4 from Figure 7.11 Generic solution to letters extraction problem
isdigit() to isalpha() in
the corresponding solution to
the digits extraction problem:

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

• numbers: list of non- • extracted odd numbers (in


negative integers the same order and quantity
that they appear in
numbers)

Table 7.11 Input and output requirements for the odd


numbers extraction problem

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

Figure 7.12 Generic solution to odd numbers extraction problem

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:

Figure 7.13 Top view of a 3 m by 2 m plot of land with 10 fenceposts

a) For each set of inputs below, fill in the expected outputs and description of steps taken to obtain the outputs:

→ Input Expected Output → Description of Steps


• width: 1
• length: 1
• width: 4
• length: 1
• width: 4
• length: 3
• width: 1
• length: 4
• width: 3
• length: 4

Table 7.12 Test cases template for fencepost counting problem

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.

7.4.1 Finding the Minimum or Maximum Value

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.

We can generalise these problems as shown in Table 7.13:

Input Output

• values: list to find • minimum_value: smallest


smallest value from value in values; None if
values is empty
• minimum_index: index of
smallest value in values;
None if values is empty

Table 7.13 Input and output requirements for the minimum


value problem

288
A solution to this problem is as follows:

Program 7.3: minimum.ipynb


1 # Input
2 values = [16, 64, 4, 128, 8, 2, 1, 32]
3
4 # Process
5 if len(values) > 0:
6 minimum_value = values[0]
7 minimum_index = 0
8 for index in range(len(values)):
9 if values[index] < minimum_value:
10 minimum_value = values[index]
11 minimum_index = index
12 else:
13 minimum_value = None
14 minimum_index = None
15
16 # Output
17 print(minimum_value)
18 print(minimum_index)

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.

Program 7.4: minimum_without_index.ipynb


1
2
3
4
5
6
7
8
9
10
11
12
13
14

Figure 7.15 Finding the minimum value of a list (no index)

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

Even though this solution is much


simpler than the previous ones, Input Output
it is still useful to understand the
algorithm in Figure 7.14 as the min() • values: list to find • maximum_value:
function does not provide the index biggest value from biggest value in
of the minimum value and cannot values; None if
be customised for more complex values is empty
situations, such as finding the second
or third smallest value in a list. • maximum_index:
index of biggest value
Besides finding the minimum value, in values; None if
we can also find the maximum value values is empty
in a list. The corresponding general
problem is as follows: Table 7.14 Input and output requirements for the maximum value problem

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

Figure 7.18 Finding the maximum value of a list (no index)

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

7.4.2 Calculating the Sum or Average

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

• values: list to calculate • total: sum of values in


the sum of values from values; 0 if values is empty

Table 7.15 Input and output requirements for the sum problem

A solution to this problem is as follows:

1
2
3
4
5
6
7
8
9
10

Figure 7.20 Finding the sum of values in a list

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

• values: list to calculate • average: average value in


the average value from values; None if values is empty

Table 7.16 Input and output requirements for the average problem

A solution to this problem is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

Figure 7.22 Finding the average value in a list

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

Figure 7.23 Finding the average value in a list using the


built-in sum() function

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.

We can generalise this problem as follows:

Input Output

• values: list to search from • search_index: index of


search in values; None if not
• search: value to search for found or values is empty

Table 7.17 Input and output requirements for the searching problem

A solution to this problem is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13

Figure 7.24 Searching for an item in a list

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.

Linear Search for 4

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

Figure 7.25 Example of linear search for 4 in an unsorted list

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.

Binary Search for 4

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

For strs, we can specify a generic extraction problem as follows:

Input Output

• original: str to extract • extract: the extracted


characters from characters
• test(): function or method
to determine whether
character should be
extracted (chosen or written
by programmer)

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

Figure 7.27 Extracting required characters from a string

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.

For lists, we can specify a generic extraction problem as follows:

Input Output

• items: list to extract • extract: the extracted items


items from
• test(): function or method
to determine whether item
should be extracted (chosen
or written by programmer)

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

Figure 7.28 Extracting required items from a list

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

Figure 7.29 Extracting required items from a list using filter()

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.

7.4.5 Splitting a String Based on Given Delimiter

In programming, we often accept input as a string


of many pieces of data separated by either spaces,
ER MS
KEY T
commas or some other delimiter that specifies the
boundary between regions of data. To process the
input properly, we would first need to split the string
Delimiter
into a list containing the required pieces of data.
One or more characters that specify the
boundary between regions of data
For instance, a common format for distributing tabular
data is as comma-separated values or CSV. To process
this data, we would first need to transform a typical
line in CSV format like 'Alex,Male,15' into a list like
['Alex', 'Male', '15'].

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.

Table 7.20 Input and output requirements for the string


splitting problem

A possible solution to this problem is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

Figure 7.31 Splitting a string based on a given delimiter

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

['a', '', '', 'b', '', '', 'c']

Figure 7.32 Sample run of string splitting solution

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())

['a', 'b', 'c']

Figure 7.33 Using str's split() method without any arguments

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:

print('a b c'.split(' '))

['a', '', '', 'b', '', '', 'c']

Figure 7.34 Using str's split() method with explicit delimiter

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:

Enter item, blank to end: 19

Enter item, blank to end: 65

Enter item, blank to end: -20

Enter item, blank to end: 24

Enter item, blank to end:

-20 19

Figure 7.36 Sample run – Test Case 1

Enter item, blank to end: -19

Enter item, blank to end:

None

Figure 7.37 Sample run – Test Case 2

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.

You are not allowed to use sum().

Assume that the input data will always be valid.

Two test cases for how the program should behave with different inputs are as follows:

Enter length: 4

Enter item: 20.24

Enter item: -19.65

Enter item: 202.5

Enter item: 2.030

74.92

Figure 7.38 Sample run – Test Case 1

301
QUICK
E C K 7.4
CH
Enter length: 0

None

Figure 7.39 Sample run – Test Case 2

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

['a', 'b', 'c']

Figure 7.40 Sample run of modified string splitting solution

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

The following are some test cases for this problem:

→ Input Expected Output → Explanation


99,99 2 The largest absolute change is 99 - 99 = 0 from day 1 to day 2.

0,3,6,2 4 The largest absolute change is 6 - 2 = 4 from day 3 to day 4.

1,3,5,6,4,7,9,11 6 The largest absolute change is 7 - 4 = 3 from day 5 to day 6.

Table 7.21 Test cases for largest absolute change problem

Write the required program.

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:

# Program 7.19: count_characters.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 # Output
12 print(counts)

Enter string: Abracadabra

{'A': 1, 'b': 2, 'r': 2, 'a': 4, 'c': 1, 'd': 1}

Figure 7.41 Counting the frequency of characters in a string

Adapt this program to:

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.

c) Output the input string with all unique characters excluded.

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

The following are some test cases for this problem:

→ Input Expected Output → Explanation


12,56,9,0,70,66,20 Thursday The highest number of items sold is 70 on Thursdays.

12,56,9,0,70,66,20 Monday The highest number of items sold is 56 + 99 = 155 on Mondays.


20,99,4,10,20,40,11

12,56,9,0,70,66,20 Monday The highest number of items sold is 56 + 99 + 0 = 155 on Mondays.


20,99,4,10,20,40,11
0,0,0,99,0,0,0

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.

The following are some test cases for this problem:

→ Input Expected Explanation


Output →
basketball.txt football.txt 3 The two lists have 3 names (Alex, Bala and
Siti) in common.
Alex Alex
Bala Anand
Daniel Bala
Faisal Jiayi
Siti Siti
Xavier Ziggy

basketball.txt football.txt 0 The two lists have no names in common.


Alex Anand
Bala Ben
Faisal Daniel
Jiayi Siti
Xavier Ziggy

Table 7.23 Test cases for the sports festival problem

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---*
-*---------*-
--*-------*--
---*-----*---
----*@@@*----
-----*@*-----
------*------

It is guaranteed that the input is valid.

Write the required program.

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.

The following are some test cases for this problem:

→ Input Expected Output →


• pieces: ['a', 'b', 'c'] 'a,b,c'
• delimiter: ','
• pieces: ['', 'b', '', ''] '!!b!!!!'
• delimiter: '!!'
• pieces: ['Hello'] 'Hello'
• delimiter: ' '
• pieces: [] ''
• delimiter: ','

Table 7.24 Test cases for join()

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.

The following are some test cases for this problem:

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

• message: 'Test' Test


• borders: ''
• message: '' AAAAAA
• borders: 'ABC' ABBBBA
ABCCBA
ABCCBA
ABCCBA
ABBBBA
AAAAAA

Table 7.25 Test cases for nested box decoration problem

8. You are tasked to write a program that converts integers from 0 (inclusive) to 999,999 (inclusive) into English
words.

The following are some test cases for this problem:

→ Input Expected Output →


0 zero
1 one
11 eleven
21 twenty-one
42 forty-two
100 one hundred
101 one hundred and one
111 one hundred and eleven
1000 one thousand
1001 one thousand and one
1100 one thousand one hundred
1111 one thousand one hundred and eleven
4242 four thousand two hundred and forty-two
42042 forty-two thousand and forty-two
42121 forty-two thousand one hundred and twenty-one
100001 one hundred thousand and one
999999 nine hundred and ninety-nine thousand nine hundred and
ninety-nine

Table 7.26 Test cases for number to text problem

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.

b) Write the required program.

ANSWER

Pg. 280-Quick Check 7.2


1. a) This task can be broken down into:
• A task for converting a temperature from °F to °C
• A task for classifying a temperature in °C into a category
b) A possible answer is as follows:
def convert_to_celsius(f):
return (f - 32) * 5 / 9

def classify_temp(t):
if t < 20:
return "Cold"
elif t < 30:
return "Moderate"
elif t < 35:
return "Warm"
else:
return "Hot"

temp = float(input('Enter temperature in Fahrenheit: '))


temp_celsius = convert_to_celsius(temp)
print(classify_temp(temp_celsius))

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

3. A possible answer is as follows:

message = input('Enter message: ')

# Begin with answer for empty message


result = '*'
# Extend answer gradually to consider more characters of message
for c in message:
result += c + '*'

print(result)

Pg. 287-Quick Check 7.3


1. a) A possible answer is as follows:
→ Input Expected Output → Description of Steps
• width: 1 4 • First and last rows in top view each need
• length: 1 (width + 1) = 2 fenceposts

• There are no other rows which need


fenceposts
• Hence, total fenceposts needed is 2 × (width +
1) + 0 = 4

• width: 4 10 • First and last rows in top view each need


• length: 1 (width + 1) = 5 fenceposts

• There are no other rows which need


fenceposts
• Hence, total fenceposts needed is 2 × (width +
1) + 0 = 10

• width: 4 14 • First and last rows in top view each need


• length: 3 (width + 1) = 5 fenceposts

• There are (length - 1) = 2 rows which each


need 2 fenceposts

• Hence, total fenceposts needed is 2 × (width +


1) + (length - 1) × 2 = 14

308
ANSWER

→ Input Expected Output → Description of Steps


• width: 1 10 • First and last rows in top view each need
• length: 4 (width + 1) = 2 fenceposts

• There are (length - 1) = 3 rows which each


need 2 fenceposts

• Hence, total fenceposts needed is 2 × (width +


1) + (length - 1) × 2 = 10
• width: 3 14 • First and last rows in top view each need
• length: 4 (width + 1) = 4 fenceposts

• There are (length - 1) = 3 rows which each


need 2 fenceposts

• Hence, total fenceposts needed is 2 × (width +


1) + (length - 1) × 2 = 14

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

2 × (width + 1) + (length - 1) × 2 = 2 × (width + height).


Hence, a possible answer is:
width = int(input('Enter width: '))
length = int(input('Enter length: '))
print(2 * (width + length))

2 . a) A possible answer is as follows:


def is_vowel(c):
return c.upper() in 'AEIOU'

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

c) A possible answer is as follows:

1 original = input('Enter string: ')


2
3 def is_vowel(c):
4 return c.upper() in 'AEIOU'
5
6 result = ''
7 for c in original: # Loop through all the characters as c
8 if not is_vowel(c): # Check if c is not a vowel
9 result += c # If so, include c
10 print(result)

Pg. 301-Quick Check 7.4


1. A possible answer is as follows:
# Program: two_smallest.ipynb
1 # Input
2 values = []
3 while True:
4 item = input("Enter item, blank to end: ")
5 if item == "":
6 break
7 values += [int(item)]
8
9 # Process
10 if len(values) >= 2:
11 # Start with solution for just first two items in values.
12 if values[0] < values[1]:
13 minimum_value = values[0]
14 second_minimum_value = values[1]
15 else:
16 minimum_value = values[1]
17 second_minimum_value = values[0]
18 # Extend solution beyond the first two items.
19 for value in values[2:]:
20 if value < minimum_value:
21 second_minimum_value = minimum_value
22 minimum_value = value
23 elif value < second_minimum_value:
24 second_minimum_value = value
25 else:
26 minimum_value = None
27 second_minimum_value = None
28
29 # Output
30 if minimum_value == None:
31 print("None")
32 else:
33 print(minimum_value, second_minimum_value)

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)

3. A possible answer is as follows:


# Program: split_str_modified.ipynb
1 # Input
2 s = input('Enter s: ')
3 delimiter = input('Enter delimiter: ')
4
5 # Process
6 pieces = []
7 current = 0 # Track start index of current piece
8 while True:
9 delimiter_start = s.find(delimiter, current)
10
11 if delimiter_start == -1:
12 piece = s[current:]
13 if piece != '':
14 pieces += [piece]
15 break
16
17 piece = s[current:delimiter_start]
18 if piece != '':
19 pieces += [piece]
20 current = delimiter_start + len(delimiter)
21
22 # Output
23 print(pieces)

Pg. 302-Review Questions


1. A possible answer is as follows:
visitors_str = input('Enter visitors: ')

# Split and cast to int


visitors = []
for piece in visitors_str.split(','):
visitors += [int(piece)]

# Begin with solution for visitors[0] and visitors[1]


max_index = 1
max_diff = abs(visitors[1] - visitors[0])

# Extend solution to visitors[2], visitors[3], etc.


for i in range(2, len(visitors)):
diff = abs(visitors[i] - visitors[i-1])
if diff > max_diff:
max_index = i
max_diff = diff

# Output should be max_index + 1 since index 0 corresponds to day 1


print(max_index + 1)

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)

b) A possible answer is as follows:


# Program: check_all_unique.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 result = True
12 for c in counts:
13 if counts[c] > 1:
14 result = False
15 break
16
17 # Output
18 print(result)

c) Output the input string with all unique characters excluded.


# Program: count_characters.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 result = ''
12 for c in s:
13 if counts[c] != 1:
14 result += c
15
16 # Output
17 print(result)

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

days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',


'Thursday', 'Friday', 'Saturday']
max_index = 0 # Start with totals[0]
for i in range(1, 7): # Then check totals[1], totals[2], etc.
if totals[i] > totals[max_index]:
max_index = i
print(days[max_index])

4. A possible answer is as follows:


with open('basketball.txt') as f:
basketball = f.read().split('\n')
with open('football.txt') as f:
football = f.read().split('\n')

count = 0
for name in basketball:
if name in football:
count += 1

print(count)

5. A possible answer is as follows:


with open('image.txt') as f:
dimension = int(f.readline()) # Treat first line specially
lines = f.read().split('\n') # Read rest of file into a list

for row in range(dimension):


line = ''
for column in range(dimension):
# By manually solving small instances of the problem,
# 1. using lines[row][column] produces normal image
# 2. using lines[dimension - column - 1][row] rotates image
line += lines[dimension - column - 1][row]
print(line)

6. A possible answer is as follows:


def join(pieces, delimiter):
if len(pieces) == 0:
return ''
result = pieces[0]
for piece in pieces[1:]:
result += delimiter + piece
return result

7. A possible answer is as follows:


message = input('Enter message: ')
borders = input('Enter borders: ')

def decorate(lines, border):


"""
Returns given list of lines enclosed in a box with given border.
Each line in lines must have the same length.
"""
length = len(lines[0])
result = [border * (length + 2)]
for line in lines:
result += [border + line + border]
result += [border * (length + 2)]
return result

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)

print(borders + message + borders[::-1])

for i in range(len(borders))[::-1]: # Reverse of first part


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.

b) A possible solution is as follows:


belowtwenty = ['zero', 'one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine', 'ten', 'eleven',
'twelve', 'thirteen', 'fourteen', 'fifteen',
'sixteen', 'seventeen', 'eighteen', 'nineteen']

tens = [None, None, 'twenty', 'thirty', 'forty', 'fifty', 'sixty',


'seventy', 'eighty', 'ninety']

def convert_belowhundred(number):
""" Convert numbers from 0 to 99 inclusive. """
# Numbers below 20 inclusive are special.
if number < 20:
return belowtwenty[number]

# Otherwise, get the word for the tens place.


tens_words = tens[number // 10]

# 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)

# Otherwise, get the words for the hundreds place.


hundreds_words = belowtwenty[number // 100] + ' hundred'

# 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)

# Otherwise, get the words for the thousands place.


thousands_words = (convert_belowthousand(number // 1000) +
' thousand')

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))

number = int(input('Enter number: '))


print(convert(number))

315

You might also like