Help support the author by donating or purchasing a copy of the book (not available yet)



Chapter 5 - Looping & Iterations

Important Note:

This chapter may be a fair bit more challenging than the previous chapters and there is a lot to take in here.

5.1 - while loops

Let's say we wanted to do something over and over again. At the moment we'd have to write out the same piece of code over and over. This isn't practical. What if we wanted to do something 100 times or 10,000 times?

In this chapter we look at looping and iteration, in particular, the while loop. While loops are syntactically very similar to if statements.

# IF STATEMENTS
if <condition>:
    # Do something
    # And another thing
    
    
# WHILE LOOPS
while <condition>:
    # Do something
    # And another thing

As with if statements, the <condition> is a boolean expression. The body also contains a sequence of statements. Similarly, the extent of body of the loop is determined by the indentation of the statements.

The way they work however is slightly different and they operate as follows:

  1. Evaluate the condition.
  2. If the condition evaluates to False, then skip the body of the while loop and execute the subsequent statements.
  3. Otherwise, if the condition evaluates to True:
  4. Execute the body of the loop
  5. Return to step 1.

Let me illustrate this with an example

x = True                    #  <- Assign True to x (x contains True)
while x == True:            #
    print("Hello")          #
    x = False               #
print("x is now false")     #

-------------------------------------------------------------------------------

x = True                    #
while x == True:            #  <- Evaluate the expression (evaluates to True)
    print("Hello")          #
    x = False               #
print("x is now false")     #

-------------------------------------------------------------------------------

x = True                    # 
while x == True:            #
    print("Hello")          #  <- Print "Hello" to the terminal window
    x = False               #
print("x is now false")     #

-------------------------------------------------------------------------------

x = True                    #
while x == True:            #
    print("Hello")          #
    x = False               #  <- Assign False to x (x contains False)
print("x is now false")     #

------------------------------------------------------------------------------

x = True                    #
while x == True:            #
    print("Hello")          #
    x = False               #  <- We've reached the end so re-evaluate condition
print("x is now false")     #

------------------------------------------------------------------------------

x = True                    #
while x == True:            #  <- Evaluate the expression (it fails, so exit loop)
    print("Hello")          #     (If it didn't we'd go around the loop again.)
    x = False               #
print("x is now false")     #

------------------------------------------------------------------------------

x = True                    #  
while x == True:            #
    print("Hello")          #
    x = False               #
print("x is now false")     #  <- Print "x is now false" to terminal window

Lets look at another example.

i = 0
while i < 5:
    print(i)
    i = i + 1
    
# THE OUTPUT
0
1
2
3
4

This might look a little confusing but let me explain what's going on. The variable i is called a counter (or loop variable) and it controls the number of times the loop iterates.

What if we were to have the condition as i < 10000? Our 4 lines of code would still hold and the program would count from 0 to 9999.

You may be wondering why we counted from 0 as it seems unnatural but there are good reasons for this. It will be explained in greater detail in chapter 24.2 but let me give an example.

Remember I said you can think of memory as cubbyholes? Well lets take that example:

-------------------------------------
|        |        |        |        |   # Each "cubbyhole" is a *memory location*
-------------------------------------


-------------------------------------
|        |        |        |        |   # Each has an *address*
-------------------------------------


-------------------------------------
|   32   |   44   |   89   |   12   |   # Suppose these are filled with values
-------------------------------------


-------------------------------------
|   32   |   44   |   89   |   12   |   # Let's say the address of the first location is 2
-------------------------------------
    ^
    |
    2
    
# WE NEED A FORMULA TO ACCESS THE Nth MEMORY LOCATION FROM HERE. 
# SUPPOSE WE WANT TO ACCESS THE LOCATION HOLDING 89.
# WELL THATS: current_address + 2 (2 + 2 = 4 which is the address that contains 89)
# THIS FORMULA NEEDS TO BE GENERAL SO IF WE WANTED THE FIRST LOCATION
# THAT WOULD BE: current_address + 0 (2 + 0 = 2 which is the address of first location)

We don't actually count from 0 we start indexes (which we will get to later) with 0. It's just good practice to count from 0 in loops like this and I recommend getting used to it.

As a rule of thumb the counter should begin at -1, 0 or 1 or something around those numbers. It's very rare to see counters beginning at something like 30 and there is usually a very, very good reason for doing so.

Let's look at another example. We'll write a program that allows the user to input 3 numbers and we'll add them up and print the result.

total = 0

i = 0
while i < 3:
    total = total + int(input())
    i += 1
print(total)

Important: Note how I wrote i += 1. This is shorthand for i = i + 1. We could have also shortened the first statement of the loop body to total += int(input()).

5.2 - Looping patterns

You may have noticed in the previous while loop examples we had a re-occurring pattern (or structure) to our loops.

There are two patterns we usually follow when writing while loops. These are:

  1. Do-something-n-times
  2. Do-while-not-condition

I'll get to the second pattern in a minute but for now I'll look at the first pattern.

We have been using the first pattern in the previous examples which is as follows:

while i < N:
    # Do something
    i += 1

In the above pattern, we know the value of N prior to evaluating the loops condition. It may have come from user input or it may be the result of some previous calculation.

As a naming convention, it's good practice to name the counter as i and if i is being used as a variable name somewhere else, then j or k will do.

Here's another example which may seem to go against this pattern upon thinking about the problem but what if we wanted to count backwards, so instead of 0, 1, 2, we wanted 2, 1, 0 (You're probably thinking we should do i = i - 1)?

Here is how it's done but the user inputs the number we're counting backwards from:

n = int(input())

i = 0
while i < n:
    print(n - i - 1)
    i += 1

Great! We're still conforming to the pattern.

Let's take a look at the second looping pattern, the "Do-while-not-condition" pattern. With this pattern we don't know how many times we'll go around the loop before it terminates.

It's structure is as follows:

while not <condition>:
    # Do something

Each pattern has their uses so let's look at an example where this pattern could be used.

Suppose the user inputs numbers some number of times, we don't know how many times yet, and our condition is that they can't input a negative number:

number = int(input())

while not number < 0:
    print(number)
    number = int(input())
print("You entered a negative number")

In this example we continuously ask the user for a number and print it. We continue like this until they input a negative number in which case the condition fails and the loop terminates.

To recap:

Important Note:

If you are using the "Do-something-N-times" pattern, don't forget to increment i! Forgetting to increment the value of this variable may lead to something called an infinite loop and these are bad! If you are doing a counting loop for example, like the one we have seen above, and you're counting to 10 and forget to increment i, your program will count past 10 and continue on forever. Infinite loops can lead to your computer slowing down or even worse, freezing. So be careful!

5.3 - break and continue

In this section I'm going to discuss two new statements. The break statement and the continue statement. There is a bit of a debate around when and where you should use them and what is best practice regarding the use of these statements but I'll talk about that a little later on in this section.

The break statement is used to exit the loop by skipping the rest of the loop's code block without testing the condition for the loop. break interrupts the flow of the program by breaking out of the loop and continues to execute the rest of your program.

The break statement is used as follows:

while <condition 1>:
    # Statements
    if <condition 2>:
        break
    # More statements
# Rest of your program

Here's an example of it in action:

number = 10

i = 0
while i < number:
    if i == 5:
        break
    print(i)
    i += 1
print("Exiting program")

# OUTPUT
0
1
2
3
4
Exiting program

I think it's quite self explanatory how break works so let's take a look at the continue statement.

The continue statement is used to skip the remaining statements in the body of the loop and start the next iteration of the loop. Unlike the break statement, continue doesn't terminate the loop, it just jumps back to the start.

The continue statement is used as follows:

while <condition 1>:
    # Statements
    if <condition 2>:
        continue
    # More statements
# Rest of your progam

Here's an example of it in action:

number = 5

i = -1
while i < number:
    i += 1
    if i == 2:
        continue
    print(i)
print("Exiting program")

# OUTPUT
0
1
3
4
Exiting program

Notice how this has kind of messed up our looping pattern as we had to put i += 1 as the first statement and we had to initialize i to -1.

Now this is a trivial case but continue has its uses. Let's look at when and where these statements should be used. For now though, I recommend avoiding them and don't use them as a crutch to get out of a loop. For the most part, in this book, if you find yourself using these statements theres usually something wrong with your loop and you should think about the problem a bit more.

When used at the start of a loop's code block, they act like preconditions. A precondition is a condition placed on something (loop, function, etc) which must hold true at the beginning of that "something" in order for it work correctly.

When placed at the end of the loop's code block, they act like postconditions. A postcondition is a condition placed on something which must hold true after the execution of that "something" in order to be satisfied that it has executed correctly.

Now this next one might be a bit confusing so don't get too caught up in it, I'm putting it here for completeness.

These statements may also be used as invariants, in particular, loop invariants. An invariant is a statement that is placed in a code segment that is repeated (loops for example) and should be true each time about the loop. Invariants are often used in loops and recursion (which we will get too later).

This part may be confusing. If an invariant is placed at the beginning of a while loop whose condition doesn't change the state of the computation (that is, it has no side effects), then the invariant should also be true at the end of the loop. When used in object oriented programming (which we'll also get to later), invariants can refer to the state of an object.

For now though, avoid them, especially in the exercises later on.

5.4 - while loop examples

As I've said before, while loops can be confusing when starting out with them so I'm going to give some more examples of them in action before we move onto exercises.

Example 1

The first example problem is to check if a given number is a prime number assuming the given number is greater than or equal to 2. Here's the code:

n = int(input())

i = 2
while i < n and (n % i) != 0:
    i += 1
if i < n:
    print("Your number is not a prime number")
else:
    print("Your number is a prime number!")

Try and figure out why I have the if/else statements by working it out on some paper with small numbers.

Example 2

The next example is going to be an extension to the Fizz-Buzz program you've written before. There is a slight change though. Last time you wrote a program that prints the number, fizz, buzz or fizz-buzz for a given number. This time I'm going to write a program that prints the sequence up to a given number.

n = int(input())

i = 1
while i < n:
    if i % 3 == 0 and i % 5 == 0:
        print("fizz-buzz")
    elif i // 3 == 0:
        print("fizz")
    elif i // 5 == 0:
        print("buzz")
    else:
        print(i)
    i += 1

Notice the order the if/elif/else statements go in. Since in Python statements are executed sequentially, we need to check that the number isn't divisible by both 3 and 5 first.

Example 3

In this example program we're going to write a program that allows the user to continuously enter numbers until they enter the number 0. When they enter the number 0 we'll print out the total of all the other numbers they inputted.

number = int(input())

total = 0
while not number == 0:
    total += number
    number = int(input())
print(total)

If you now feel a bit more comfortable with while loops then lets look at some problems for you to solve!

5.5 - Exercises

Important Note:

The solutions to some of these exercises require thinking outside-the-box. Don't expect to arrive at a solution immediately!

These exercises take a step up in difficulty so think carefully about your solutions.

Question 1

Write a program that prints the first n numbers of the Fibonacci sequence. The Fibonacci sequence is defined as :


$$ F_n = F_{n-1} + F_{n-2} \\ F_0 = 0, F_1 = 1 $$

That is, the next number in the sequence is the sum of the previous two numbers and the first two numbers in the sequence are 0 and 1. A part of the sequence is shown below:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

Question 2

Write a program that prints a sequence such as the one shown below. The number of stars in the widest part should be equal to the number a user inputs:

# INPUT
7

# OUTPUT
*
**
***
****
*****
******
*******
******
*****
****
***
**
*

Question 3

This question may require some extra reading. So head over to chapter 24.2 to learn about binary numbers (especially converting binary numbers to decimal).

Computers understand binary numbers however, most of us don't (unless you can read them). Write a program that converts a 4 bit binary number into its decimal equivalent. Here's some examples of the outputs expected based on the inputs

input    output
---------------
0000     0
0001     1
0010     2
0011     3
0100     4
0101     5

Question 4

Write a Python program that reads in a single integer from the user. Then read in 3 more integers, each time printing whether or not the number was higher or lower than the previous. You can assume that every number is different. Here is an example input and output:

# INPUT
5
2
9
7

# OUTPUT
lower
higher
lower


Help support the author by donating or purchasing a copy of the book (not available yet)



Previous Chapter - Next Chapter