# Looping

## Loops

### `while` loops

Many times we desire a process to continue until some condition is met. For instance, a user creating a new password may need to include both upper- and lower-case letters, and one or more numbers. In this case, we would write a possible `while` loop to enforce this condition as follows:

``````password_attempt = ''
``````

#### Definition

A `while` loop consists of the following:

``` while condition: block ```

where `condition` is any expression that yields a `bool` and `block` is the code which should be repeated.

Warning! `while` loops are susceptible to infinite looping if the truth condition cannot be met. Make sure that the variables involved in ```condition change during the loop (in block). ```

#### Examples

This code counts down from 10 to 1 and prints a message:

``````number = 10
while number > 0:
print(number)
number -= 1
print('Blast off!')
``````

This code sums all of the digits in a number:

``````number = 12145
string = str(number)
i = 0
sum = 0
while i < len(string):
sum += int(string[i])
``````

This code contains an infinite loop, since `i` is never updated:

``````i = 1
while i < 10:
print(i)
``````

To break out of such a loop, press `Ctrl`+`C` to stop Python.

#### Design pattern: Accumulator

Design patterns are structures we commonly encounter in writing code. The accumulator pattern uses an accumulator variable to track a result which changes inside of a loop:

``````i = 0
sum = 0
while i <= 4:
sum += i
i += 1
``````

In this code, both `i` and `sum` are playing the role of accumulators.

### `for` loops

In contrast to `while` loops (which repeat forever until a condition is met), we frequently need to repeat a process for each thing in a group. Consider the following two `for` loops:

``````# Loop #1
# print the title-case version of each color
colors = [ 'red', 'yellow', 'blue', 'jale', 'ulfire' ]
for color in colors:
print( color.title() )
``````
``````# Loop #2
# print the square of each number from zero to sixteen
for i in range(0, 16):
print( i ** 2 )
``````

Although looping over different things (`colors` is a `list` and `range(0,16)` you may not have seen yet), you can see that they each define a new variable (`color` and `i`) and use it once for each element in the list.

Explicitly, each time through the first loop `color` has a different value. The following code is equivalent:

``````color = colors
print( color.title() )
color = colors
print( color.title() )
color = colors
print( color.title() )
color = colors
print( color.title() )
color = colors
print( color.title() )
``````

and of course we don't have `colors` so the process halts.

#### Definition

A `for` loop consists of the following:

``` for value in values: block ```

where `value` is the loop variable, `values` is the set of things which `value` assumes in turn, and `block` is the code which should be repeated for each `value`. Although `values` may be defined before the loop or in the `for` statement itself, `value` is created as a new variable in the `for` statement. We refer to something that can be iterated over in a `for` loop as iterable. Iterables you have seen thus far include `str`ings and `list`s.

#### Examples

This code counts down from 10 to 1 and prints a message:

``````for number in range(10):
print(10-number)
print('Blast off!')
``````

This code sums all of the digits in a number:

``````number = 12145
string = str(number)
sum = 0
for i in range(len(string)):
sum += int(string[i])
``````

An alternative solution:

``````number = 12145
string = str(number)
sum = 0
for c in string:
sum += int(c)
``````

### Controlling loops: `continue` and `break`

Sometimes we need to exit a loop completely—perhaps there was invalid input or some threshold value was exceeded. Or perhaps we need to just skip to the next item, but not stop iterating. In these cases, we can rely on the `continue` and `break` statements.

The `break` statement is more "powerful"—it stops a loop and prevents any further iterations from taking place:

``````for j in range(0,8):
if j == 4:
break
print(j)
``````

The foregoing loop will only output the numbers `0,1,2,3` before terminating.

In contrast, the `continue` statement lets you "short-circuit" a single iteration:

``````for j in range(0,8):
if j == 4:
continue
print(j)
``````

This latter loop will output all of the numbers except 4: `0,1,2,3,5,6,7`.

#### Examples

This `while` loop will continue forever until you give it a valid number:

``````while True:
x = input( 'Please enter a number:' )
if x.isdigit():
break
``````

### Nesting loops

Consider a field experiment in which data need to be gathered on plankton for four different species at three different lakes. To make sure that we analyze the data properly (given a function `analyze`), we can write a pair of nested `for` loops:

``````sites = [ 'Lake Calumet', 'Lake Vermilion', 'Ferne Clyffe Lake' ]
species = [ 'Melosira granulata', 'Chroomonas minuta',
'Oscillatoria rubescens', 'Chlamydomonas spp.' ]

for lake in sites:
for sp in species:
analyze(sp, lake)
``````

In this case, all twelve cases are quickly and succinctly analyzed by the pair of `for` loops.

Any number of loops may be nested inside of each other, depending on program needs. One common task is to loop over each dimension in a list of lists:

``````data = [ [ 0.0, 0.2, 0.1 ],
[ 0.4, 0.2, 0.6 ],
[ 0.9, 0.3, 0.1 ] ]
for row in data:
for value in row:
print( value )
``````

Alternatively:

``````data = [ [ 0.0, 0.2, 0.1 ],
[ 0.4, 0.2, 0.6 ],
[ 0.9, 0.3, 0.1 ] ]
for x in range( len(data)):
for y in range( len(data[x]) ):
print( data[x][y] )
``````

### `enumerate` function

The two major approaches to `for` loops include explicitly selecting each member of a container in turn, or using a counter to index the container:

``````my_list = [ 1, 6.5, 'Hartree' ]
# loop over members of container
for item in my_list:
print( item )
# or use a counter:
for i in range( len(my_list) ):
print( my_list[i] )
``````

What if we would like both, for convenience? That is, we want both an item and an index? We can rely on the `enumerate` function, which pairs an index and an item together:

``````for i,item in enumerate( my_list ):
print( '%s is the %ith item in the list.'%(item,i) )
``````

The first value is the count, or index, of the `list`'s item. The second value is the item itself.

### `zip` function

Sometimes two `list`s correspond to each other. In this case, you can either explicitly index both `list`s or you can use the handy `zip` function:

``````letters = [ 'A', 'B', 'C', 'D' ]
numbers = [ 1, 2, 3, 4 ]
for letter, number in zip( letters,numbers ):
print( '%s pairs with %i'%( letter,number ) )
``````

`list`s should be of the same length when you use `zip`.

#### Resources

##### Clone this wiki locally
You can’t perform that action at this time.