Which loop is used when certain statements need to be executed repeatedly until a condition is fulfilled?

The other type of important programming control structure is a repetition statement. A repetition statement is used to repeat a group (block) of programming instructions. Most beginning programmers have a harder time using repetition statements than they have at using selection statements. At the same time, the use of repetition statements is at least (if not more) important than using selection statements. Therefore, it is a good idea to expect to spend more time trying to understand and use repetition statements.

Repetition statements fall into two general categories; while loops and for loops. Although it is possible to write every loop as a while loop (or every loop as a for loop), this is not a good idea. While loops should be used if the number of repetitions is not fixed. In many cases, the number of repetitions that a while loop executes depends on user input. On the other hand, for loops should be used when the number of repetitions is fixed. In many cases, the number of repetitions a for loop executes for is determined by the number of elements in an array or an array-like object (such as a list or a tuple in Python). This is why for loops are often associated with some indexed quantity like a list.

While loops

As mentioned earlier, while loops are used when a block of statements have to be repeated, but the number of repetitions is not a fixed amount. This means that a while loop might repeat two times when a program is run and repeat a different number of times the next time that same program is run. This feature makes while loops flexible. Unfortunately (as mentioned before), this flexibility comes at the expense of being more complex.

A good way to start thinking about how while loops work is to think in terms of the following algorithm:

While the task is not done repeat these instructions

This gives a feel for why while loops don't always repeat the same number of times. It may take a different number of repeats for the task to get done. Actually, the above algorithm is lacking in some important details. The next algorithm fills in those important details.

While (condition 1 is true) do some instruction(s) If (condition 2 is true) Set condition 1 to be false

What this algorithm suggests is that most while loops have two conditions that are involved. As long as condition 1 is true, the while loop repeats. But, a selection statement (based on a second condition) will cause condition 1 to become false at some point to end the loop. The important thing to take note of here is that somewhere in the while loop's block, there must be some instructions that cause condition 1 to be false. Otherwise, the while loop becomes an infinite loop (a loop that repeats forever).

To get a better feel for writing a while loop, consider the following program. You want to write a program that will be asking for the names of all the members in a club. However, we don't know how many members are actually in the club. Thus, once the while loop starts, the while loop will simply repeat until all the member's names have been entered. The following is an algorithm that could be used to solve this problem.

Create an empty list called names Set doneEntering to false While (not doneEntering) Ask user to enter a name or leave blank if done, store in name Strip whitespace from name, store in name If (name is blank) Set doneEntering to true Else Append name to names print names

We need to have someplace to store the names that are entered. Thus the first line of this algorithm just indicates creating a list to store those names in. Next, we define a variable named doneEntering and set its value to be false. This means that we are not done entering names at this point. Since doneEntering is set to false, the condition “not doneEntering” is true so the while loop starts. The user is prompted to enter a name or to hit enter without an name to end the input. When the input is read in, any leading or trailing whitespace (spaces, tabs, carriage returns) is stripped off. If the user enters a blank string, the while loop ends. Otherwise, the name that is read in gets appended (added on to the end) to the names list. Finally, once the while loop is done, the names list is printed out.

The following shows that algorithm turned into Python code:

names = [] # creates empty list called names doneEntering = False while (not doneEntering): name = input("Enter a name, or leave blank when done: ") name = name.strip() if (name == ""): doneEntering = True else: names.append(name) print(names)

Line 1 creates an empty list called names. Note that everything after the pound (#) symbol is treated as a comment. Line 2 sets doneEntering to false. The boolean value for false in Python must be spelled with a capital 'F' or False. Similarly, on line 7 the boolean value for true is True. You need to remember to capitalize the first letter for those boolean values.

Lines 3-9 define the while loop. Think of line 3 as saying "while we're not done entering, do the following (lines 4-9)". On line 5 we prompt for a name or ask them to enter a blank if done. Line 5 strips the leading and trailing whitespace from name. Line 6 checks to see if name is an empty string. If this is the case, doneEntering is set to True and the while loop ends. Otherwise, name is appended to the names list.

Once the while loop is completed, line 10 prints out the list of names. Here is a sample run of this program:

$ python3 while_names.py Enter a name, or leave blank when done: Jane Enter a name, or leave blank when done: John Enter a name, or leave blank when done: Bill Enter a name, or leave blank when done: Bob Enter a name, or leave blank when done: Alexander Enter a name, or leave blank when done: ['Jane', 'John', 'Bill', 'Bob', 'Alexander']

Another approach to the while loop's logic

The preceding example uses a kind of negative logic approach to while loops. That is, the loop continues “while not done”. It is possible to use the opposite logic for while loops. The following algorithm serves as a simplified view of this approach.

While (still Running) Do something

We can redo the previous program using this different approach to the logic. Here is the modified algorithm:

Create an empty list called names Set stillEntering to true While (stillEntering) Ask user to enter a name or leave blank if done, store in name Strip whitespace from name, store in name If (name is blank) Set stillEntering to false Else Append name to names print names

Turning this to code would result in:

names = [] stillEntering = True while (stillEntering): name = input("Enter a name, or leave blank when done: ") name = name.strip() if (name == ""): stillEntering = False else: names.append(name) print(names)

The lines that are changed from the previous program are lines 2, 3 and 7. They just set up the test condition in a reverse way to the previous program. Otherwise, the program is basically the same program.

Still another approach to while loops

The while loop can also be set up so that the test condition for stopping is tested on the first line of the while loop. This removes that selection statement from the body of the while loop.

Here is the same program modified so that just a single test condition is used:

names = [] name = "nonblank" while (name != ""): name = input("Enter a name, or leave blank when done: ") name = name.strip() names.append(name) print(names)

As you can see, this version is shorter. This is because the selection statement no longer occurs in the body of the while loop. However, a sample run will demonstrate that this program is not exactly the same as the previous ones:

$ python3 while_names3.py Enter a name, or leave blank when done: Jane Enter a name, or leave blank when done: John Enter a name, or leave blank when done: Bill Enter a name, or leave blank when done: Alexander Enter a name, or leave blank when done: ['Jane', 'John', 'Bill', 'Alexander', '']

Notice that this version adds an extra blank string at the end of the list. We can get around this problem without adding a selection statement within the while loop by changing the loop into a pre-test loop instead of a post-test loop.

Pre-test vs. Post-test loops

Up until the last version of the program, we have been dealing with post-test loops. These are while loops that must run at least one time because the test condition that terminates the while loop is at the end of the while loop. On the other hand, a pre-test loop checks the terminating condition at the beginning of the while loop. This means that a pre-test while loop may not even execute once.

To set up a pre-test loop, you need to write instructions that allow the while test condition to be tested before the while loop starts. The following shows how this is done for the new version of the program:

names = [] name = input("Enter a name, or leave blank when done: ") name = name.strip() while (name != ""): names.append(name) name = input("Enter a name, or leave blank when done: ") name = name.strip() print(names)

In this version of the program, we have set up a pre-test loop. On lines 2 and 3 we read in a name (or blank string) and strip the whitespace from the name. If the user enters a blank string at this point, the while loop that starts on line 4 never executes. This means that when the names list is printed on line 8, an empty list is printed.

On the other hand, if the user enters a name, the while loop starts. The first thing that is done inside the while loop is that the name is appended on to the names list (see line 5). Having the append occur before the next input makes it so that when the user enters a blank string to end input, the while loop exits before appending that blank string to the names list.

Here is a sample run of this latest version of the program:

$ python3 while_names4.py Enter a name, or leave blank when done: Jane Enter a name, or leave blank when done: John Enter a name, or leave blank when done: Bill Enter a name, or leave blank when done: Alex Enter a name, or leave blank when done: ['Jane', 'John', 'Bill', 'Alex']

Using a pre-test loop solves the problem. You should experiment writing while loops with the different styles shown here and find what seems to make the most sense to you. Then, stick to that way of writing while loops.

While loops - self-test

Here are a few questions on while loops that you can use to test your understanding.

Question 1

Write a program that uses a while loop. This while loop will simply ask the user to enter 'done' to end the while loop. If the user enters anything besides 'done', the while loop will continue. Here is a sample run of the program:

$ python3 question1.py Enter 'done' to end this loop: a Enter 'done' to end this loop: funny Enter 'done' to end this loop: little Enter 'done' to end this loop: loop Enter 'done' to end this loop: done

done = False while (not done): entry = input("Enter 'done' to end this loop: ") entry = entry.strip().lower() if (entry == "done"): done = True

Question 2

Write a program that uses a while loop to add names of club members into a list. The names should be stored in the title format. The while loop should end when the user enters a blank string for input. After the while loop ends, the program should print the list of members. Here is a sample run:

$ python3 question2.py Enter a member's name or leave blank when done: jane doe Enter a member's name or leave blank when done: John doE Enter a member's name or leave blank when done: BiLl gaTeS Enter a member's name or leave blank when done: ['Jane Doe', 'John Doe', 'Bill Gates']

members = [] moreMembers = True while (moreMembers): member = input("Enter a member's name or leave blank when done: ") member = member.strip() if (member == ""): moreMembers = False else: members.append(member.title()) print(members)

Question 3

Write a program that uses a while loop to allow entry of some test scores. The while loop should continue until the user enters 'done' instead of a score. After the while loop is completed, the program should print out the total score, and the average score. Here is a sample run of the program:

$ python3 question3.py Enter a score or 'done' if complete: 80 Enter a score or 'done' if complete: 87 Enter a score or 'done' if complete: 90 Enter a score or 'done' if complete: 83 Enter a score or 'done' if complete: done Total score: 340.0 Average score: 85.0

total = 0 count = 0 done = False while (not done): score = input("Enter a score or 'done' if complete: ") score = score.strip() if (score.lower() == "done"): done = True else: score = float(score) total = total + score count = count + 1 print("Total score:",total) print("Average score:",total/count)

For loops

For loops are repetition statements that are made to iterate over a set of values. This makes for loops very useful for manipulating arrays and array-like objects (such as lists). Unlike while loops, for loops are designed to repeat a set number of times. This gives a for loop an obvious starting and stopping point.

For loops in the Python language are set up somewhat differently than in languages such as C, C++, or Java. In languages such as C, for loops make use of a loop variable. This loop variable controls the start, the end, and the step-size for the loop. Consider the following Java program:

class ForLoop { public static void main(String[] args) { for (double x = 3; x < 20; x += 3.7) { System.out.println(x); } } }

In this Java program, x is the loop variable. The for loop starts with x = 3 and continues until x reaches 20 or more. Each time through the for loop, x increases by 3.7. When this program is run, this is the output:

$ java ForLoop 3.0 6.7 10.4 14.100000000000001 17.8

So in Java (similar to C and C++), the first line of the for loop determines the range of values the loop will cover. This is different from how for loops in Python are set up.

For loops in Python require an array-like object

Unlike the for loop we have just seen, for loops in Python require an array-like object (such as a list or a tuple) to iterate over. Consider the following example:

for i in [1,2,3]: print(i)

The loop variable i takes on every value in the list, [1,2,3], and that value is printed out. Here is the output:

$ python3 for1.py 1 2 3

To produce the same output as the Java program, one way to would be with a program like this:

for x in [3.0,6.7,10.4,14.1,17.8]: print(x)

That would produce nearly the same output as the Java program. (The output would show 14.1 instead of 14.100000000000001, because of the way Java handles floating point numbers.) But, that does not seem to be a very practical way of producing such a result. This is where the range() function comes into play.

The range() function

The range() function generates an iterable object based on the three arguments passed to that function. The basic syntax is this:

range(start,end,increment)

To get a feel for how range() works, here are some examples in Python interactive mode:

>>> for x in range(1,10,1): ... print(x) ... 1 2 3 4 5 6 7 8 9

The loop variable, x, starts at 1, increments by 1 and ends just before 10 can be reached.

>>> for y in range(0,5,2): ... print(y,end=' ') ... 0 2 4

The loop variable, y starts at 0, increments by 2 and ends before 5 can be reached.

>>> for num in range(0,6): ... print(num,end=' ') ... 0 1 2 3 4 5

If you leave off the increment, an increment of 1 is used.

>>> for num in range(10,1,-1): ... print(num, end=' ') ... 10 9 8 7 6 5 4 3 2

Negative increments can also be used. Note that the range ends before 1 can be reached. Now, let's see about setting up a range that will generate the list we wanted:

>>> range(3,20,3.7) Traceback (most recent call last): File "", line 1, in TypeError: 'float' object cannot be interpreted as an integer

Unfortunately, the range() function only works with integers, not floats. If you installed python-numpy, that module has a function called arange() that can use increments that are floats. But, installing a whole module just to get that functionality seems overkill. This just illustrates how Python's for loops are made to iterate over lists. A better solution would probably be to use a while loop:

>>> start = 3 >>> end = 20 >>> while (start < end): ... print(start,end=' ') ... start = start + 3.7 ... 3 6.7 10.4 14.100000000000001 17.8

Although this works, it is not a general solution. However, this is not something to worry about for our course. We will have many practical examples where it is easy to generate the list the for loop has to iterate over.

For loops are made for manipulating lists

In Python, for loops and lists go hand in hand. Here are a few examples of how for loops and lists can be used.

Getting the total of a list of numbers

Here is an example of finding the total of a list of numbers. This example uses the accumulator pattern.

mylist = [1,5,3,16] total = 0 for i in range(0,len(mylist)): total = total + mylist[i] print("total is",total)

The accumulator pattern is where you initialize a variable, total, to zero and add to this variable each time through the for loop. This variable accumulates the values to obtain a total value.

Note on line 3 how the len() function is used. The len() function returns the number of elements in a list. The len() function can also return the number of characters in a string. In this case, by returning the number of elements in the list, the for loop will iterate over all of the list elements.

It is useful to go over in some detail exactly what is going on in this program. Line 1 just defines a list of numbers called mylist. Line 2 defines the accumulator variable, total. On line 3, the range() function is used with the len() function. Since there are 4 elements in mylist, len(mylist) will return a 4. This means that we have range(0,4), and that returns this list: [0,1,2,3]. For the for loop, that means that i will take on the values in that list.

So, the first time through the for loop, i = 0. The value of mylist[0] is 1. So total = 0 + 1 = 1, after the first pass through the for loop.

For the second pass through the for loop, total is already 1 from the first pass. For this pass, i = 1. The value of mylist[1] is 5. So total = 1 + 5 = 6, after the second pass.

For the third pass through the for loop, total is already 6 from the second pass. For this pass, i = 2. The value of mylist[2] is 3. So total = 6 + 3 = 9, after the third pass.

For the last pass through the for loop, total is already 9 from the third pass. For this pass, i = 3. The value of mylist[3] is 16. So total = 9 + 16 = 25, and the for loop ends. This is the value that is shown when this program is run:

$ python3 total_list.py total is 25

Alternative form for obtaining total of list of numbers

There is another way to set up for loops in Python. This style is called the for-each style, although the word for is still used. Here is the same calculation using the for-each style of for loop:

mylist = [1,5,3,16] total = 0 for number in mylist: total = total + number print("total is",total)

On line 3, number is set as the loop variable. But by specifying the list name (instead of a range), this loop variable will take on the value of each element in the list. That means the first time through the for loop, number = 1. The second time through the for loop, number = 5. The third time through the for loop, number = 3, and the last time through the for loop, number = 16.

For most people, the for-each style of for loop is easier to understand and definitely less error-prone. Therefore, it is the preferred way of using for loops in Python. However, it should only be used if you are doing the same process for each element of the list the for loop is iterating over.

The previous method for setting up the for loop uses the index of the list to select the element from the list. That is why that method is referred to as the index-based for loop.

✴ ✴ ✴ ✴ ✴

To decide whether to use an index-based for loop or a for-each style for loop is straightforward. If the for loop will process all of the elements in the list the same, use the for-each style. If the for loop will process only some of the elements in a list, or if the for loop will treat some elements in the list different from other elements, then use the index-based for loop.

✴ ✴ ✴ ✴ ✴

Printing out all elements in a list, one on each line

For loops are good for printing out all the elements in a list, one on each line. Here is a simple program illustrating this:

animals = ["cat","dog","pig","cow"] for animal in animals: print(animal) print("") for i in range(0, len(animals)): print(animals[i])

This program uses both styles of for loops. Line 4 just prints out a blank line in between the two outputs. Here is a sample run of this program:

$ python3 print_list.py cat dog pig cow cat dog pig cow

As you can see, both for loops do the same thing. But, the first version is easier and is preferred.

Converting a list of strings into a list of numbers

Suppose we have a list of strings that needs to be converted into a list of numbers. A for loop can be used to do that. If we want to convert the elements in place (that is use the same list), we need to use an index-based for loop:

mylist = ["5","10","13","27"] for i in range(0, len(mylist)): mylist[i] = float(mylist[i]) print(mylist)

If you want to create a new list with the numbers that are obtained by converting the strings in the original list, you could use a for-each style for loop. This requires using the append() function of lists, that adds an element to the end of a list.

mylist = ["5","10","13","27"] mylist2 = [] for item in mylist: num = float(item) mylist2.append(num) print(mylist2)

This is a little more work than the index-based for loop version, but it can be done. We will do a lot more with for loops and lists when we study file input. For now, you can try the following self test.

For loops - self-test

Here are a few questions on for loops that you can use to test your understanding.

Question 1

Write a program that starts with a list of numbers. The program starts by printing out that list. Then, the program uses a for loop to calculate the average value of that list. Here is a sample run of the program:

$ python3 question1a.py mylist: [28, 32, 47, 62, 14] average 36.6

mylist = [28,32,47,62,14] print("mylist:",mylist) total = 0 for num in mylist: total = total + num print("average",total*1.0/(len(mylist)))

Question 2

Consider the following program. On scratch paper, analyze the program and write down the output that you think the program will produce:

for i in range(0,3): for j in range(1,4): print("i is",i,"j is",j)

i is 0 j is 1 i is 0 j is 2 i is 0 j is 3 i is 1 j is 1 i is 1 j is 2 i is 1 j is 3 i is 2 j is 1 i is 2 j is 2 i is 2 j is 3

Question 3

Write a program that asks the user to enter an integer greater than 1. The program will calculate the average of the list of numbers going from 1 up to and including the number the user entered. Here are three sample runs of the program:

$ python3 question3a.py Enter an integer greater than 1: 5 average: 3.0 $ python3 question3a.py Enter an integer greater than 1: 10 average: 5.5 $ python3 question3a.py Enter an integer greater than 1: 20 average: 10.5

num = input("Enter an integer greater than 1: ") num = int(num) total = 0 count = 0 for i in range(1,num+1): total = total + i count = count + 1 print("average:",total/count)