Looping - Or the art of repeating oneself!

What will we cover?

In the last exercise we printed out part of the 12 times table. But it took a lot of typing and if we needed to extend it, it would be very time consuming. Fortunately there is a better way and it's where we start to see the real power that programming languages offer us.

"for" Loops

What we are going to do is get the programming language to do the repetition, substituting a variable which increases in value each time it repeats. In Python it looks like this:

>>> for n in range(1,13):
...    print( "%d x 12 = %d" % (n, n*12) )
...
1 x 12 = 12
2 x 12 = 24
3 x 12 = 36
4 x 12 = 48
5 x 12 = 60
6 x 12 = 72
7 x 12 = 84
8 x 12 = 96
9 x 12 = 108
10 x 12 = 120
11 x 12 = 132
12 x 12 = 144

Note 1: The for line ends with a colon (:). This is important since it signifies to Python that what follows is the thing to be repeated.

Note 2: We need the range(1,13) to specify 13 because range() function generates from the first number up to, but not including, the second number. (range can actually generate much more sophisticated sets of numbers but for our purposes a simple sequence suffices.) This may seem somewhat bizarre at first but there are reasons and you do get used to it!

Note 3: The for operator in Python is actually a foreach operator in that it applies the subsequent code sequence to each member of a collection. In this case the collection is the list of numbers generated by range(). Alternatively we could just replace range() with an explicit list of numbers like this:

>>> for n in [1,2,3,4,5,6,7,8,9,10,11,12]:
...     print( "%d x 12 = %d" % (n, n*12) )

Note 4: The print line is indented or spaced further in than the for line above it. That is a very important point since it's how Python knows that the print is the bit to repeat. There can be more than a single line indented too, Python will repeat all of the lines that are indented for each item in the collection. Also, it doesn't matter how much indentation you use so long as it's consistent. (Python will tell you if it isn't!)

Note 5: In the interactive interpreter you need to hit Return twice to get the program to run. The reason is that the Python interpreter can't tell whether the first one is another line about to be added to the loop code or not. When you hit Return a second time Python assumes you're finished entering code and runs the program.

Phew! That was a lot of notes! However, now we have considered the syntax of a for loop let's consider how it works. Let's step through it step by step.

First of all, python uses the range() function to generate a list of numbers from 1 to 12. It does this through a special mechanism called a generator which is like a list that is built up one item, at a time, on demand. This has the advantage of saving memory if it is a long list. It is also why we had to explicitly generate the list with list() when we printed range() above. You may recall we had to do a similar thing with dictionary keys() way back in the Raw Materials topic.

Next python makes n equal to the first value in the list, in this case 1. It then executes the bit of code that is indented, using the value n = 1:

   print( "%d x 12 = %d" % (1, 1*12) )

Python then goes back to the for line and sets n to the next value in the list, this time 2. It again executes the indented code, this time with n = 2:

   print( "%d x 12 = %d" % (2, 2*12) )

It keeps repeating this sequence until it has set n to all the values in the list. At that point it moves to the next command that is not indented - in this case there aren't any more commands so the program stops.

Here's the same loop in VBScript:

The simplest VBScript loop construct is called a For...Next loop, and is used as shown:

<script type="text/vbscript">
For N = 1 To 12
    MsgBox N & " x 12 = " & N*12
Next
</script>

This is much more explicit and easier to see what is happening. The value of N varies from 1 through to 12 and the code before the Next keyword is executed. In this case it just prints the result in a dialog box as we've seen before. The indentation is optional but makes the code easier to read. As with Python, the loop body (the bit that gets executed) can contain more than the single line used here.

Although the VBScript appears, at first glance, more obvious, the Python version is ultimately more flexible as we'll see shortly.

And in JavaScript

JavaScript uses a for construct that is common in many programming languages, being modeled on C. It looks like this:

<script type="text/javascript">
for (n=1; n <= 12; n++){
    document.write(n + " x 12 = " + n*12 + "<BR>");
    };
</Script>

Note: This construct initially looks quite complicated. It has 3 parts inside the parentheses:

Notice also that JavaScript encloses the repeated code (the loop body) in braces {} and although that is all that is needed, technically speaking, it is considered good practice to indent the code inside the braces too, just to improve readability.

The loop body will only execute if the test part is true. Each of these parts can contain arbitrary code but the test part must evaluate to a boolean value.

More about the Python for construct

The Python for loop iterates over a sequence. A sequence in Python, lest you forgot, includes things like strings, lists and tuples. (In fact Python can iterate over several other kinds of things too but we will discuss them much later in the tutorial.) Thus we can write for loops that act on any type of sequence. Let's try printing the letters of a word one by one using a for loop with a string:

>>> for c in 'word': print( c )
...
w
o
r
d

Notice how the letters were printed, one per line. Notice too that where the body of the loop consists of a single line we can add it on the same line after the colon(:). The colon is what tells Python that there's a block of code coming up next.

We can also iterate over a tuple:

>>> for word in ('one','word', 'after', 'another'): print (word)
...

This time we got each word on a line. We can put them all on one line using a special feature of the print() function. We can add an extra argument after the printable item, like this:

>>> for word in ('one', 'word', 'after', 'another'): print( word, end='' )
...

See how the words now appear as a single line? The end='' part told Python to use an empty string ('') as the line ending instead of the newline character that it uses by default.

We have already seen for with a list but for completeness we will do it once more:

>>> for item in ['one', 2, 'three']: print( item )
...

There is one caveat when using foreach style loops like this. The loop gives you a copy of what was in the collection, you can't modify the contents of the collection directly. So if you need to modify the collection you have to use an awkward kludge involving the index of the collection, like this:

myList = [1,2,3,4]
for index in range(len(myList)):
    print( myList[index] )
    myList[index] += 1
print( myList )

That will increment each entry in myList. If we had not used the index trick we would simply have incremented the copied items but not changed the original list. Also note that we now have a multi-line body in our loop.

The enumerate function

The example above is so common that Python provides a convenience function to avoid the problem (or at least to alleviate the pain). It's the enumerate function which, when applied to a collection returns two items at a time: the collection value plus its index number. This allows us to access the value as we did in the original for loop and to modify it via the index as we did in the example above. It looks like this:

     myList = [1,2,3,4]
     for index, value in enumerate(myList):
         print( value )
         myList[index] += 1
     print( myList )    
     

Note that in this example I have not used the interactive Python prompt (>>>), so you need to type this into a file as described in the More sequences topic. If you do try typing it at the >>> prompt you will need to add extra blank lines to tell Python when you finish a block, for example after the myList[index] += 1 line. It's actually quite a good way of learning where blocks start and stop: to type the code in and see if you correctly guess where an extra line will be needed. It should be where the indentation changes!

The other gotcha with foreach loops is that you can't delete items from the collection that you are iterating over, otherwise the loop will get confused. It's a bit like the old cartoon character cutting off the branch of a tree while sitting on it! The best way to deal with this situation is to use a different kind of loop, which we are going to discuss next. However, to understand how to remove elements safely we need to wait until we cover yet another topic, that of branching, so we will explain this subject when we get there.

It's worth noting that VBScript and JavaScript each have loop constructs for looping over the elements in a collection. I won't discuss them in detail here, but the VBScript construct is for each...in... and the JavaScript version is for...in... You can look them up in the relevant help pages if you want to see the details.

"While" Loops

For loops are not the only type of looping construct available. Which is just as well, since for loops require us to know, or be able to calculate in advance, the number of iterations that we want to perform. So what happens when we want to keep doing a specific task until something happens but we don't know when that something will be? For example, we might want to read and process data from a user until the user tells us to stop, so we won't know in advance how many data items the user wants to have processed. We just want to keep on processing data until the user says enough. That's possible but kind of tricky, in a for loop.

To solve this problem we have another type of loop: the while loop.

It looks like this in Python:

>>> j = 1
>>> while j <= 12:
...    print( "%d x 12 = %d" % (j, j*12) )
...    j = j + 1

Let's walk through what's happening.

  1. First we initialize j to 1, initializing the control variable of a while loop is a very important first step, and a frequent cause of errors when missed out.
  2. Next we execute the while statement itself, which evaluates a boolean expression ( j<=12 in our case).
  3. If the result is True it proceeds to execute the indented block which follows. In our example j is less than 12 so we enter the block.
  4. We execute the print statement to output the first line of our table.
  5. The next line of the block increments the control variable, j. In this case it's the last indented line, signifying the end of the while block.
  6. We go back up to the while statement and repeat steps 4-6 with our new value of j.
  7. We keep on repeating this sequence of actions until j reaches 13.
  8. At that point the while test will return False and we skip past the indented block to the next line with the same indentation as the while statement.
  9. In this case there are no other lines so the program stops.

By now that should feel pretty straightforward. Just one thing to point out - do you see the colon (:) at the end of the while (and for) lines above? That just tells Python that there's a chunk of code (a block) coming up. As we'll see in a moment, other languages have their own ways of telling the interpreter to group lines together, Python uses a combination of the colon and indentation.

VBScript

Let's look at VBScript's version of the while loop:

<script type="text/vbscript">
DIM J
J = 1
Do While J <= 12
    MsgBox J & " x 12 = " & J*12
    J = J + 1
Loop
</script>

This produces the same result as before but notice that the loop block is delimited by the keyword Loop. Other than that it works pretty much exactly like the Python one.

The VBScript Do...Loop construct is actually a very versatile structure and we can build several variants that each have slightly different effects. You can choose the one that reads best for your particular application from the following options:

Do...Loop
The most basic form that just loops forever. (There is a way to get out of it which we cover in a later topic.)
Do While <test>...Loop
This is the variation we looked at above
Do Until <test>...Loop
Very similar to the option above but the test logic is reversed
Do...Loop While <test>
Like a while loop but because the test is at the end the loop body will always execute at least once.
Do...Loop Until <test>
Like the above except the test logic is reversed

JavaScript

<script type="text/javascript">
j = 1;
while (j <= 12){
   document.write(j + " x 12 = "+ j*12 + "<BR>");
   j++;
   }
</script>

As you see the structure is pretty similar just some curly brackets or braces instead of the Loop in VBScript. (Remember that j++ in JavaScript means increment the value of j) Note that unlike Python, neither VBScript nor JavaScript need any indentation, that's purely to make the code more readable.

Finally it's worth comparing the JavaScript for and while loops. Recall that the for loop looked like this:

for (j=1; j<=12; j++){....}

Now, that is exactly the same structure as the while loop, just compressed into one line. The initializer, the test condition and the loop modifier are all there clearly seen. So in fact a JavaScript for loop is simply a while loop in a more compact form. It would be possible to do without the for loop completely and only have while loops, and that's exactly what some other languages do.

More Flexible Loops

Coming back to our 12 times table at the beginning of this section. The loop we created is all very well for printing out the 12 times table. But what about other values? Can you modify the loop to make it do the 7 times table say? It should look like this:

>>> for j in range(1,13):
...    print( "%d x 7 = %d" % (j,j*7) )

Now this means we have to change the 12 to a 7 twice. And if we want another value we have to change it again. Wouldn't it be better if we could enter the multiplier that we want?

We can do that by replacing the values in the print string with another variable. Then set that variable before we run the loop:

>>> multiplier = 12
>>> for j in range(1,13):
...    print( "%d x %d = %d" % (j, multiplier, j*multiplier) )

That's our old friend the 12 times table. But now to change to the seven times, we only need to change the value of 'multiplier'. Try typing this program into a Python script file and running it from a command prompt. Then edit the multiplier value to try out some different tables.

Notice that we have here combined sequencing and loops. We have first a single command, multiplier = 12 followed, in sequence by a for loop.

Looping the loop

Let's take the previous example one stage further. Suppose we want to print out all of the times tables from 2 to 12 (1 is too trivial to bother with). All we really need to do is set the multiplier variable as part of a loop, like this:

>>> for multiplier in range(2,13):
...    for j in range(1,13):
...       print( "%d x %d = %d" % (j,multiplier,j*multiplier) )

Notice that the part indented inside the first for loop is exactly the same loop that we started out with. It works as follows:

  1. We set multiplier to the first value (2) then go round the second, inner loop.
  2. Then we set multiplier to the next value (3) and go round the inner loop again,
  3. and so on.

This technique is known as nesting loops.

One snag is that all the tables merge together, we could fix that by just printing out a separator line at the end of the first loop, like this:

>>> for multiplier in range(2,13):
...    for j in range(1,13):
...       print( "%d x %d = %d" % (j,multiplier,j*multiplier) )
...    print( "------------------- " )

Note that the second print statement lines up with the second 'for', it is the second statement in the loop sequence. Remember, the indenting level is very important in Python.

Just for comparisons sake let's see how that looks in JavaScript too:

<script type="text/javascript">
for (multiplier=2; multiplier < 13; multiplier++){
    for (j=1; j <= 12 ; j++){
        document.write(j, " x ", multiplier, " = ", j*multiplier, "<BR>");
        }
    document.write("---------------<BR>");
    }
</script>

Experiment with getting the separator to indicate which table it follows, in effect to provide a caption. Hint: You probably want to use the multiplier variable and a Python format string.

Other loops

Some languages, such as VBScript as described above provide more looping constructs. However, some kind of for and while are usually there. (Modula 2 and Oberon only provide while loops since while loops can simulate for loops - as we saw above.) Other loops you might see are:

do-while
Same as a while but the test is at the end so the loop always executes at least once.
repeat-until
Similar to above but the logic of the test is reversed.
GOTO, JUMP, LOOP etc
Mainly seen in older languages, these usually set a marker in the code and then explicitly jump directly to that marker.

Points to remember

Previous  Next