Repetition (loop)
Sometimes we wish to repeat something with a specific schedule and until a specific deadline. Repetition happens in our daily life. We wake up in the morning, attend our classes until we graduate from college. This is a schedule that repeats daily and finishes when the student graduates. There are many more things that we repeat at various speeds and deadlines. To solve problems with computers, we need ways to tell the CPU to repeat some of our instructors with a specific schedule.
Repetition needs three components:
- start of the repetition,
- steps towards completing the repetition, and
- the end of the repetition.
For example, a computer program may be required to receive a list of numeric values from the user and print the average of those values on the screen. We have learned before that we can do this simply by calling the built-in sum
and len
functions. However, one might wonder how those functions work? How does sum
compute the sum of the values in a list L
and how does len
count the number of elements in L
?
These and many other functions work using repetition statements, specifying the start of the repetition (start of the list), the progress towards the end of the repetition (examining each element in the list), ending with an end condition (end of the list).
If we wanted to describe how sum
works without using a digital computer, we'd follow the following procedure. Given a list of numbers L
, a variable s=0
, and a counter variable i=0
,
- start with the ith element
e
ofL
and add it tos
. - Next, advance
i
with one. - Check if
i < len(L)
, repeat Step 1. Otherwise, stop.
For example, given the following as the list L
, we will start with i=0
(the first index in the list) and s=0
, a variable to keep track of the sum of the elements. Starting with the first element, we will add 5 to s
and add one to i
. Then, we check if i < len(L)
, which means checking if 1 < 10
. The condition is true. Step 3 says that we now should go back to Step 1. We will now add 9 to s
, which makes the value of s
14, and add one to i
, making it 2. This continues until i
becomes 10, in which case the condition i < len(L)
becomes false.
5 | 9 | 0 | 12 | 3 | 4 | 8 | 8 | 6 | 7 |
To write the steps above in Python, we need a way to write a repetition statement. One such statement is called a while loop:
while condition:
body
A while-loop starts with a condition (an expression with a Boolean value). If the condition is true, similar to an if-statement, the body of the while loop is executed. The difference with an if-statement is that when the body of the if-statement is executed, the computer moves on to the statement after the if-statement. With the while loop, when the computer finishes the execution of the body, it checks the condition again. If the condition is still true, the body of the while loop is executed again. This is repeated until the condition of the while loop becomes false.
One way to use a while loop is using an iterator variable. We set an initial value for the iterator variable, define the condition of the while loop for a limit on the value of the iterator, and increment the value of the iterator inside the body of the while loop. This way, we can start, increment, and end using the iterator variable. Going back to the procedure above, we can write the program using an iterator-based while loop.
L = list(map(eval,input().split()))
s = 0
i = 0
N = len(L)
while i < N:
s+= L[i]
i+=1
This program receives a list of numeric values from the user. Then, the variable s
, called the accumulator, keeps track of the sum of the values in the list that we have checked so far. The iterator i
helps us to go through each element in L
as it starts with index 0 and ends with index len(L)-1
. The end is specified in the condition of the while loop (i < N
). Inside the while loop, we add the current element in L
to our accumulator s
. To progress towards the end of the list, we advance the iterator by adding one to it.
Infinite loops
An infinite loop is a loop that never ends. That means, the condition used in the loop never becomes False. Recall that we have to always specify how a loop proceeds towards the end. The end of the loop is when its condition is False.
while True:
value = int(input('Enter a value: '))
print('Good bye')
This program has an infinite loop because the condition for the loop is True, which is impossible to become False. The reason is that True is a direct Boolean value, not an expression that can be changed. So, this program keeps asking for new input in each iteration of the loop. An iteration is a full execution of the body of the loop (that is, the statements inside the loop). Notice that the last statement in this program is never executed and the sentence "Good bye" will never be printed on the screen.
Break & Continue
There are ways to break an infinite loop, making infinite loops actually useful. One is the use of the break
statement, which can be placed inside a loop, causing the loop iteration to stop and the execution to move to the statement after the loop.
while True:
value = int(input('Enter a value: '))
if value == -1:
break
print('Good bye')
In this program, the break statement is used after checking a sentinel value, which is a value that is used to determine whether we should end the execution of a while loop. The program keeps iterating until the user enters -1
, making the if
-statement to be executed. Inside the if
-statement, the break
statement stops the execution of the while loop immediately. Then, the computer executes the print function and terminates the program.
Another way to change the way a loop is executed is to use the continue
statement. The continue
statement works similar to the break
statement in that it will immediately stop the execution of the current statement. However, instead of breaking the loop and executing the statements after the loop, it will just continue to the next iteration.
while True:
value = int(input('Enter a value: '))
if value < 0:
break
if value % 2 != 0:
continue
print(value)
print('Good bye')
In this program, the loop is only broken when the value is negative. However, the continue
statement breaks the iteration when the value is not divisible by 2. As a result, the print
function inside the while
-loop is only executed when the value of 2 is divisible by 2.
A complete guessing game
Continuing the guessing game that we described earlier, we would like to give the user a chance to play again and guess the number that the computer picks. To do this, we will have to use a loop.
import random
x = random.randint(0,30)
while True:
guess = int(input('Guess the value of x: '))
if guess == x:
print('You made it 😄')
break
elif abs(guess - x) <= 2:
print("You're very close 😅")
elif abs(guess - x) >= 8:
print("You're very far away 🙃")
else:
print('Try harder 🧐')
This program continues as long as the user has not guessed the value of x
correctly. Notice the first condition where we check if guess
is equal to x
. In this case, the user has guessed the value correctly. Here, we break the loop as the game is over. However, if the user did not guess the value correctly, we keep giving the user a hint and asking for a new value until the user can correctly find the value that the computer randomly generated.
As an exercise, modify the program above to only give the user 5 attempts to guess the correct value.
For-loop
Similar to the while loop, we can write a repetition using a for-loop, which works well with sequences. There are two ways of using a for-loop with sequences. One way is to loop through the elements of a sequence by making a copy of an element in each iteration. The other way is to use an index to loop through the elements of a sequence, similar to an index-based while-loop.
The range
function can be used to produce a sequence that for-loop iterates through. One can write a simple for-loop to print all positive integers up to 100 using the range
function.
for i in range(1,101):
print(i)
This loop exactly does that. Note that the range function always produces a sequence of integers starting with the first parameter and ending with the integer before the last parameter. The range function can also be used with a third parameter to designate a step size in producing the integer sequence. If we wanted to modify the code above to only write the positive odd integers up to 100, we can use the third parameter to direct the range
function to only produce odd integers.
for i in range(1,101,2):
print(i)
Here, the third parameter is the step size. That is, we're telling range
to start a sequence with 1 and add 2 to the next number until reaching 100. That is the sequence 1, 3, 5, 7, ..., 99
.
We can also loop through the elements of a list using the for-loop. In this case, we do not need the range function anymore.
x = input().split()
for x in L:
print(x)
This code receives a list of elements from the user and then uses the for-loop to checkout each element in x
in the order given by the user and print them on the screen. The for-loop iterates n times where n = len(L)
.
As a more advanced example, consider a loop that goes through the elements of a list of strings to convert each element to a numeric object. We could do this using the map function or we could do it using a for-loop.
L = input('Enter a list of numbers:').split()
n = len(L)
for i in range(0,n):
L[i] = eval(L[i])
Notice the use of the range function. Given the two arguments to the range(x,y)
function, it generates a sequence of elements from x
to y
excluding y
. The variable i
in the for-loop refers to an element from the sequence produced by range(0,n)
. The for loop starts with the first element in range(x,y)
. After each iteration, the loop automatically checks if there are more elements in range(x,y)
. If not, the loop stops. Otherwise, i
is assigned to the next element of range(x,y)
and continues with a new iteration.
Another way to use for-loops is to work directly on a sequence. To do this for the program above, we need to loop through the elements of L
and construct a new list with the converted type.
L = input('Enter a list of numbers:').split()
M = []
for x in L:
M.append(eval(x))
The reason is to store the converted element in a new list is because the for-loop does not give us access to the actual elements of L
. The variable x
is only a copy of the current element of L
.