Skip to content

Lab 02: Selection Statements and Loop Structures

Congratulations on getting this far, and welcome to the next lab! We will now start working with conditionals and repetition in this lab. The program control structures we will be going through here are fundamental to reducing redundant/repetitive code, which in itself would otherwise make code maintenance very cumbersome. Additionally, we will also run through pseudocode and flowcharts as a fundamental concept in algorithmic thinking, and how it can be essential to planning out how programs work.

Getting Started

Selection Statements

Selection statements (or conditional structures) are concerned with executing certain blocks of code or using a value dependent on whether specific conditions are fulfilled. In Python, the if-else statement has been the goto for a long time when it comes to implementing such a program control structure. However, with current and more recent versions of Python, we now also have the match case as an alternative.

The Classic if-else Statement

The classic structure for selection is the if-else statement. Using this structure, one can dedicate code sections that will be executed only if the associated condition is True. The code block under the else branch is executed if and only if the condition associated with the paired if statement is False.

if condition:
    # Code to execute if condition is True
else:
    # Code to execute if condition is False
1
2
3
4
5
age = int(input("Enter age >> "))
if age >= 18:
    print("Eligible for a driving license")
else:
    print("Ineligible for a driving license")
$ python example.py
Enter age >> 18
Eligible for a driving license
$ python example.py
Enter age >> 16
Ineligible for a driving license

The example given above only checks 1 condition; we may sometimes require checking multiple conditions. To enable checking for a second condition (assuming the first condition is not True), we add what's called an elif statement. For an associated condition (or set of conditions to be checked), there can only be 1 if statement and 1 else statement. However, we can have none or up to several elif statements in between of the if and else statements.

if condition_1:
    # Code to execute if condition_1 is True
elif condition_2:
    # Code to execute if condition_2 is True
else:
    # Code to execute if all conditions above are False
1
2
3
4
5
6
7
age = int(input("Enter age >> "))
if age >= 21:
    print("Can drive and vote")
elif age >= 18:
    print("Can drive but cannot vote")
else:
    print("Cannot drive and cannot vote")
$ python example.py
Enter age >> 20
Can drive but cannot vote
$ python example.py
Enter age >> 17
Cannot drive and cannot vote
$ python example.py
Enter age >> 24
Can drive and can vote

Additionally, sometimes no action is needed when none of the conditions laid out are met. In this case, we can safely omit use of the else statement. As such, there may be times when you will only have just one if statement under which a specific block of code will run depending on the associated condition. It is also possible for there to be the one if statement and elif statement(s) without any else statement at all.

Notice that so far, our conditions are Boolean expressions. This will also work the same way with "truthy" and "falsy" values.

Example
1
2
3
4
5
6
my_name = input("Enter your name >> ")
if my_name:     # if my_name is not falsy (in this case, an empty string '')
    # value is slotted in as part of a string template/formatted string here
    print(f"Hi, {name}!")
else:
    print("Sorry, I didn't quite get that.")

Ternary Operator

If you want to assign a value to a variable or return a value based on a condition, you can consider using Python's ternary operator.

var = value_if_true if condition else value_if_false
var = value_1 if condition_1 else value_2 if condition_2 else value_if_false

If we took the examples from earlier and use a ternary operator instead, we could get something like as follows:

example.py
1
2
3
4
age = int(input("Enter age >> "))
print("Can drive and vote" if age >= 21
      else "Can drive and vote" if age >= 18
      else "Cannot drive and cannot vote")

Note that with the ternary operator:

  • having an else statement is necesary; using this operator is discouraged if you do not have anything to assign to the value if the condition is False
  • to describe an elif statement, you have to follow this syntax: ... else ... if condition else ...
  • this is for selecting values to either be assigned to a variable or returned; you can use an expression as a substitute for a value, but not a whole code block (unless you encapsulate it in a function and call it)

match Case

The match case is a relatively new selection structure in Python (introduced in Python 3.10). This is very similar to the switch case introduced in other languages like C++ and Java, with the main difference being that instead of making equality checks, Python's match case can do more (e.g., unpack data structures, check types, etc.). Additionally, there's no need for a break statement in Python's match case - this means only the code within the associated case is executed and it does not flow down to the rest of the match case structure.

match value:
    case case_1:
        # Code to execute if value == case_1
    case case_2:
        # Code to execute if value == case_2
    case case_3:
        # Code to execute if value == case_3
    # ...
    case case_:     # Wildcard catch-all (similar to `default` in switch case)
        # Code to execute if value != all other cases
match http_code:
    case 200:
        print("Success")
    case 403:
        print("Forbidden")
    case 404:
        print("Not found")
    case 500:
        print("Internal Server Error")
    case _:
        print("Unknown Status")
1
2
3
4
5
6
7
8
9
match data:
    case int(x) if x > 1000:
        print("The value is a large integer")
    case int():
        print("The value is an integer")
    case str():
        print("The value is a string")
    case _:
        print("I don't know what data type this is")

Loop Structures

Loop structures are concerned with executing certain blocks of code several times (either definite or indefinite amount of times, or for as long as a certain condition remains True). These are the foundation of iterative code (we will explore that in Lab 07).

The for Loop

The syntax for Python's for loop is distinctively different from most existing languages. Unlike those languages where you set at most 3 statements, here you indicate specific range of values either by using Python's range() function, or by indicating the sequence whose items will be iterated over.

# starts at 0, ends before y
for counter in range(y):
    # Code to execute while loop active
# starts at x, ends before y
for counter in range(x, y):
    # Code to execute while loop active
# starts at x, ends before y, incrementing by z
for counter in range(x, y, z):
    # Code to execute while loop active
# iterate through all values in a sequence (e.g., string, list, tuple)
# the value of `c` will change in sequence of each value inside the sequence
for c in seq:
    # Code to execute while loop active

When it comes to numeric ranges, you can place anywhere between 1 and 3 integer parameters. Depending on which number of parameters you include in the range() function, they serve different purposes:

# Parameters Meaning
1 only the stop value is defined; start value is 0 by default
e.g., range(10) means iterate from 0 to 9
2 start value is defined first, followed by the stop value
e.g., range(-1, 10) means iterate from -1 to 9
3 start value is defined first, then the stop value, followed by the step value (1 by default otherwise; cannot be 0)
e.g., range(-1, 10, 2) means iterate to each second number from -1 to 9
Python Shell
>>> # iterate from 0 to 7, exclude 8
>>> for i in range(8):  # (1)
...     print(i)
...
0
1
2
3
4
5
6
7
  1. Iterator variable name need not be just i, you can use a different name for it. Keep to meaningful names if possible!
Python Shell
>>> # iterate from 4 to 7, include 4 and exclude 8
>>> for j in range(4,8):  # (1)
...     print(j)
...
4
5
6
7
>>> # iterate from 8 to 4, include 8 and exclude 4 (but nothing happens)
>>> for j in range(8,4):    # (2)
...     print(j)
>>>
  1. Here, instead of i we use j as the iterator variable name. Same meaning here!
  2. Nothing is printed since the start value is larger than or equal to the stop value. A negative step value is required to see any lines printed.
Python Shell
>>> # iterate through each second value between 2 and 7, include 2 and exclude 8
>>> for _ in range(2,8,2):  # (1)
...     print(_)
...
2
4
6
>>> # iterate through each third value between 2 and 7, include 2 and exclude 8
>>> for _ in range(2,8,3):
...     print(_)
...
2
5
  1. Note the use of the underscore _ here as the iterator variable name. This is used typically when the iterator variable does not have a notable meaning associated with it.
Python Shell
>>> # iterate through each value from 5 to 1, include 5 and exclude 0
>>> for k in range(5,0,-1):  # (1)
...     print(k)
...
5
4
3
2
1
>>> for k in range(5,0):    # (2)
...     print(k)
...
>>>
  1. The step value is set to -1 to allow decrementing of iterator variable; output is empty otherwise (i.e., nothing is printed as output). Any integer step value like 2 or -2 and further are allowed, but it cannot be 0.
  2. Nothing is printed since the start value is larger than or equal to the stop value.

With sequences, it's rather simple - just iterate through each value inside the sequence (strings, lists, tuples, dictionaries). The following examples shows how one could iterate through each character in a string, followed by iterating through each item in a list (we'll encounter this again when we get to sequences in Lab 04 and Lab 05).

Python Shell
>>> # iterate through each character in "bookworm"
>>> w = "bookworm"
>>> for c in w:
...     print(c)
...
b
o
o
k
w
o
r
m
Python Shell
>>> # iterate through each character in "hippopotamonstrosesquipedalian"
>>> for c in "hippopotamonstrosesquipedalian":
...     print(c)
...
h
i
p
p
o
p
o
t
a
m
o
n
s
t
r
o
s
e
s
q
u
i
p
e
d
a
l
i
a
n
Python Shell
>>> # iterate through each element in a list
>>> my_list = [1, 3, 5]
>>> for el in my_list:
...     print(el)
...
1
3
5

The while Loop

With the while loop, we are concerned with whether a specified condition or statement is True before continuing the looping process. This is more akin to all loop structures in many other languages, and Python's version of the while loop is similar to other programming languages that also have while-loop structures.

while cond:
    # Code to execute while loop active

Let's try to replicate one of the examples from earlier but using a while loop - iterate from 4 to 7 using the while loop - you will require 3 components:

  • init: practically a setup, which can include initialization of variable(s); in this case, we need to initialize an iterator variable (let's use j) and set the value to 4
  • cond: the condition paired with the while keyword; in this case, assuming we set the iterator variable's name as j, we can use either j <= 7 or j < 8
  • update: usually where we specify anything that will gradually break cond if needed (i.e., make cond become False); here, we need to set something similar to the step value in the for loop - increment j

Here's how it would look like in a while loop (plus another example with a different increment statement):

Python Shell
>>> j = 4           # init
>>> while j < 8:    # cond
...     print(j)
...     j += 1      # update: increment j by 1 before ending current loop
...
4
5
6
7
Python Shell
>>> j = 4           # init
>>> while j < 8:    # cond
...     print(j)
...     j += 2      # update: increment j by 2 before ending current loop
...
4
6

Here's another example where we build a randomized string up until it is 16 characters long:

Python Shell
>>> # create string with random upper case alphabets
>>> from random import randint  # (1)
>>> secret = ""                 # string to populate with random characters
>>> while len(secret) < 16:     # while `secret` is less than 16 characters long
...     secret += chr(randint(65,90))  # (2)
...
>>> secret
'YFLNTWAEDQCPXFIX'
  1. We use the randint() function from Python's random library to randomly select a number between a given range, both values included. This function is later used to select a random integer between 65 and 90 (both inclusive).
  2. After selecting a random integer between 65 and 90, it is passed into the chr() function which returns the associated character based on the given ASCII value.

Notice that here, we did not need to include update statement(s) to ensure we reach a point where the condition set is False.

continue and break

These two keywords can come in handy with skipping current iterations or prematurely halting the loop entirely.

Keyword Description
continue will break the current loop and continue with the next iteration
break will exit the loop without completing the current iteration if unfinished

Here are some examples of both these keywords in use to manipulate outputs produced by a loop structure:

Python Shell
>>> for i in range(100, 120):
...     if i % 7 == 0:  # (1)
...         break
...     print(i)
...
100
101
102
103
104
  1. The loop will break when i = 105.
Python Shell
>>> for i in range(100, 120):
...     if i % 7 == 0:  # (1)
...         continue
...     print(i)
...
100
101
102
103
104
106
107
108
109
110
111
113
114
115
116
117
118
  1. The loop will skip to the next iteration when i = 105, i = 112, and i = 119.

They can come in handy, especially if using them means requiring fewer looping structures. Here's an example where a small list of prime numbers are generated, skipping any multiple of already included numbers using break.

Python Shell
>>> my_primes = []
>>> for x in range(2, 30):
...     is_prime = True  # flag value
...     for y in my_primes:
...         # if x // y gives no remainder, x is a multiple of y
...         if x % y == 0:
...             is_prime = False
...             break
...     if is_prime:   # runs if flag variable still remains True
...         my_primes.append(x)
...
>>> my_primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

We use a flag value that flips when a target condition is achieved; here, flag variable is_prime becomes False when a composite integer is reached. The flag variable's value resets to/is initalized to True during the start of each iteration from the outer loop structure.

Python Shell
>>> my_primes = []
>>> for x in range(2, 30):
...     for y in my_primes:
...         # if x // y gives no remainder, x is a multiple of y
...         if x % y == 0:
...             break
...     else:   # runs if inner loop does not break
...         my_primes.append(x)
...
>>> my_primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Python also has a for-else structure, such that the optional else block associated with a for loop block is run when the for loop is run without premature breaking (i.e., using break).

Infinite Loops

As the name suggests, infinite loops is practically continuous and indefinite loops. This is typically frequently due to incorrect limits.

Let's look at a simple example (same one across two languages, i.e., Python and C++):

1
2
3
4
5
6
# Run this program and watch the console print an infinite sequence of numbers *forever*
# Hit CTRL + c to halt the infinite loop
i = 0  # (1)
while i < 5:
    print(i)
    i -= 1
  1. The iterator i's value is set to start from 0 and end at 5. However, since the step value is set to -1, the value of i will continuously decrease from 0. Hence, the value of i will never reach 5.
#include <iostream>
using namespace std;

int main() {
  int i = 0;
  while i < 5 {
    cout << i << endl;
  }
  return 0;
}

Here, we declare a new variable i and set its value to 0. The while loop that follows after is set as such that the looping persists as long as condition i < 5 remains True. However, as i keeps decrementing by 1 each time, the condition remains True for good. Hence, it doesn't stop (if it eventually does, I believe it usually is due to hardware interrupts). In a web browser using JavaScript, especially, infinite loops can be pretty obnoxious where the loop will effectively hang the web browser (and subsequently you'd probably have to force quit it).

Python does not recurse infinitely, though. (Well, it can, but a stack overflow error occurs when trying to call the same function more times than can be handled.)

Flowcharts

Before getting started with coding, it's best to structure out how we want the program to function - this is what's known as an algorithm.

The way you perceive what an 'algorithm' is probably incorrect.

During conversations, I often encounter people who would personify the term "algorithm" like a sort of demonic overlord everyone needs to please. I guess this is due to how we perceive the algorithm like a brain, of which serves as the model for a neural network. As such, we then begin to relate how a live human being has a functioning brain, and given how unforgiving the outcomes of said algorithm can be, we start personifying this imaginary human being with this "functioning brain" as a cruel individual who probably relishes in making misery in social media, the content creation space, etc.

If this is you, I don't fault you - I'd chalk it up to how our complex minds work anyway. However, going forward, PLEASE, PLEASE DO NOT associate the term "algorithm" as to describe some homosapien when there isn't any!

Proper definition: An algorithm comprises of a set of detailed, unambiguous, and ordered instructions that describes the processes necessary to produce the desired output from a given input.

Sometimes, this process means crafting diagrams that describe how the program works. One of the simplest diagrams that can be created is the Flowchart Diagram. A flowchart diagrammatically shows the required steps to complete a task and the order that they are to be performed.

There are other diagrams that can be used during the software design phase of what we call the software development life cycle, but this is out of scope right now - we will talk about one more type of diagram later in one of the subsequent labs when we start going through what objects are.

Flowchart Symbols

These are the symbols used in a flowchart diagram. Search up some examples online for examples (some research papers also use this, provided the flow is simple enough to use such representation).

Pseudocode Basics

Pseudocode is another simple way of showing an algorithm. You can probably find plenty of these in various research papers - I say this because while I was a research student in Sunway, I have had my fair share of times where I had to sift through several research papers with several proposed schemes that aim to solve their respective research gaps/problems.

One thing I did feel was very frustrating was when the author(s) used a non-standard way of laying out their pseudocode (if any). This ground my gears a little; it's as if there was no consistent way to write out pseudocode without making it a lazy interpretation of the real program code itself. Hopefully with this, I can at least shed some light on how I'd imagine proper pseudocode be written.

I will adhere to the following format when writing out pseudocode:

  • keywords (e.g., INPUT are to be written in upper-case)
  • names of variables will follow the same Snake Case convention as encouraged in Python, though Pascal Case or Camel Case is also welcome (just keep it consistent throughout)
  • where conditional and loop structures are used, repeated or selected statements are indented by two spaces (a usual one-finger paragraph spacing is fine if you're writing it on paper)
  • if there are no dedicated keywords in pseudocode language for a specific function (e.g., int()), you may revert to language specific notation (or preferably something that appears language agnostic)
So apparently I found out something about why different Pseudocode formatting exists..

I have since figured out some prefer a C-styled approach, which is reasonable for those who already program. That being said, I would still rather play it safe and apply something even layman folk can understand.

Assignment Statements

A value is assigned to an item/variable using the operator. The variable on the left of the is assigned the value of the expression on the right. The expression on the right can be a single value or several values combined with any mathematical operators. You may use the existing operator notations in Python, or follow a language-agnostic notation like as follows:

Mathematical Operator Meaning
+ Addition
- Subtraction
* Multiplication
/ Division
^ Exponent
() Group

Examples:

Statement Meaning
Cost <- 10 Cost has value 10
Price <- Cost * 2 Price has value 20
Tax <- Price * 0.12 Tax has the value 2.4
SellingPrice <- Price + Tax SellingPrice has the value 22.4
Gender <- "M" Gender has the value 'M'
Chosen <- False Chosen has the value False

Conditional Statements

IF cond_1
  THEN
    OUTPUT value_1
  ELSE
    OUTPUT value_2
ENDIF
IF cond_1
  THEN
    OUTPUT value_1
  ELSE
    IF cond_2
      THEN
        OUTPUT value_2
      ELSE
        OUTPUT value_3
    ENDIF
ENDIF
CASE OF value_x
  val_1: OUTPUT val_a1
  val_2: OUTPUT val_a2
  val_3: OUTPUT val_a3
  ...
  OTHERWISE OUTPUT val_a4
ENDCASE

Here's an example and the equivalent Python code:

OUTPUT "Enter mark >> "
INPUT mark
IF mark < 0 OR mark > 100
  THEN
    OUTPUT "Invalid mark"
  ELSE
    IF mark >= 40
      THEN
        OUTPUT "Pass"
      ELSE
        OUTPUT "Fail"
    ENDIF
ENDIF
1
2
3
4
5
6
7
8
mark = input("Enter mark >> ")
if not 0 <= mark <= 100:
    # OR: mark < 0 or mark > 100:
    print("Invalid mark")
elif mark >= 40:
    print("Pass")
else:
    print("Fail")

Here's another example and the equivalent Python code:

OUTPUT "Enter num_1 >> "
INPUT num_1
OUTPUT "Enter num_2 >> "
INPUT num_2
OUTPUT "Enter choice >> "
INPUT choice
CASE OF choice
  1:
    answer <- num_1 + num_2
  2:
    answer <- num_1 - num_2
  3:
    answer <- num_2 - num_1
  4:
    answer <- num_1 * num_2
  OTHERWISE
    OUTPUT "Invalid choice"
    answer <- None
ENDCASE
IF answer != None
  THEN
    OUTPUT answer
ENDIF
num_1 = input("Enter num_1 >> ")
num_2 = input("Enter num_2 >> ")
choice = input("Enter choice >> ")

match choice:
    case 1:
        answer = num_1 + num_2
    case 2:
        answer = num_1 - num_2
    case 3:
        answer = num_2 - num_1
    case 4:
        answer = num_1 * num_2
    case _:
        print("Invalid choice")
        answer = None

if answer:
    print(answer)

Loop Structures

FOR Counter <- StartVal_I TO EndVal_I
  OUTPUT Counter
NEXT Counter
FOR Counter <- StartVal_I TO EndVal_I STEP StepVal
  OUTPUT Counter
NEXT Counter
Counter <- StartVal
WHILE Counter <= EndVal DO
  OUTPUT '*'
  Counter <- Counter + 1
ENDWHILE
Counter <- StartVal
REPEAT
  OUTPUT '*'
  Counter <- Counter + 1
UNTIL Counter > EndVal

Lab Activity 01: Design First, Then Develop

I want you to hold off from programming out the solution immediately here. Read the task, draft out either a flowchart or pseudocode of how the program should go first. Then only afterwards, program out your solution based on your program design.

Task

The Body Mass Index (BMI) is a measure of health on weight. A person's BMI is calculated by taking the person's weight (in kilograms) divided by the person's height squared (height in meters). The formula to calculate a person's BMI using these two measurements (with the respective metric S.I. units) is as follows:

\[ \text{BMI} = \frac{\text{weight}}{\text{height}\times\text{height}} \]

Create a BMI script that takes in both a person's weight and height as values to interpret the person's BMI. The respective BMI interpretations are as follows:

  • BMI \(\le\) 18.5: Underweight
  • 18.5 \(\leq\) BMI \(\le\) 25.0: Normal
  • 25.0 \(\leq\) BMI \(\le\) 30.0: Overweight
  • BMI \(\geq\) 30.0: Obese
Enter weight (in kg) >> 68
Enter height (in m) >> 1.7
Your BMI is 23.53 (Normal)
Enter weight (in kg) >> 0
Weight must be positive!
Enter weight (in kg) >> 68
Enter height (in m) >> -1.7
Height must be positive!
Enter height (in m) >> 1.7
Your BMI is 23.53 (Normal)
Enter weight (in kg) >> 103.2
Enter height (in m) >> 1.8
Your BMI is 31.85 (Obese)
Enter weight (in kg) >> 78.4
Enter height (in m) >> 1.67
Your BMI is 28.11 (Overweight)

Extra considerations:

  • Both weight and height are scalar values, so negative values. No zeros either.
  • If any of these two required inputs is negative, print an error message and prompt the user for the associated input again. (refer to Sample Output 2)

Extra Task

Modify the program to ask the user if the weight and height are provided in metric units (kg and m respectively) or imperial units (lb. and in. respectively). The formula to calculate a person's BMI given the weight and height in imperial units is as follows:

\[ \text{BMI} = \frac{\text{weight}}{\text{height}\times\text{height}} \times 703 \]

Lab Activity 02: Turtle Again

The following code produces a drawing of a parallelogram as follows:

from turtle import *


bk(100)
rt(45)
bk(100)
lt(45)
fd(100)
rt(45)
fd(100)
lt(45)

Parallelogram turtle Drawing

Create a regular 32-petal flower drawing with this parallelogram. You are required to use a loop structure for this activity; excluding import statements and any empty lines, the maximum total number of lines is 12. Try experimenting use of the for and while loops and see which solution feels easier to come up with.

Parallelogram 32-petal Flower Drawing

Lab Activity 03: Simon Says

Simon Cowell
Picture Source: nbc.com

"Simon Says" is a simple game one person (regarded as "Simon") gives instructions to the other players. The other players then need to follow the instructions that start with "Simon says", and disregard those that do not start with "Simon says" otherwise.

The game to be implemented in Python is simple - it continues as long as we do not accidentally follow instructions that do not start with "Simon says" or disregard instructions that do. The way how instructions are followed or disregarded is by entering a number associated with the appropriate action.

Here are some potential instructions to implement (you can add more if you so please):

  1. Cover your nose
  2. Cover your eyes
  3. Cover your ears
  4. Shrug
  5. Clap your hands
  6. Do nothing

Here's a sample output of how the game should run:

Start with the given code below:

Starting Code
from random import randint


def print_instructions(lst):
    print("Instructions:")
    x = 1
    for item in lst:
        print(f"{x}. {item.capitalize()}")
        x += 1
    print()


instructions = [
    "cover your nose",
    "cover your eyes",
    "cover your ears",
    "shrug",
    "clap your hands",
    "do nothing",
]
print_instructions(lst)

rand_num = randint(0,1)
current_instruction = instructions[randint(1, len(instructions))]
if rand_num == 0:
    print(current_instruction.capitalize())
else:
    print("Simon says " + current_instruction)
response = int(input("Response >> "))

When the code is run, the program first prints out the list of potential instructions, followed by a prompt from Simon (which may or may not include the prefix "Simon says"). The program then requests for a keyboard input (of which is to capture the number associated with an instruction).