# A series that converges to the value of $\pi$More about loops
We have already encountered one way of repeating calculations - the while loop. Python also provides a second kind of loop, the for loop. This allows us to do a calculation for each of the entries in a list, tuple or dictionary (or, more generally, any object that can yield a well-defined return value each time it is called).
The For loop
Typically, a for loop takes the form:
for <variable> in <collection>:
    [calculations using <variable>]As with the while loop, everything within the indented block is executed multiple times, with the <variable> getting set equal to a different element of <collection> on each pass. <collection> may be any ‘iterable’, such as a list. For example, the following code would calculate the sum of all the entries in a:
a = [1, 5, 9]
s = 0
for x in a:
    s += x
    print(x, s)
print("Total is:", s)It is possible to use continue [go to the next iteration immediately] and break [terminate the loop immediately] statements within a for loop, just as in a while loop.
Often, we simply want to perform a calculation \(n\) times, counting off as we go. To allow this, Python provides the range function, which is a special kind of iterable. It can be used as follows:
n = 20
for i in range(n):
    print(i)By default, the counting starts from 0, and continues up to \(n-1\) (so that there are a total of \(n\) passes through the loop). If you want to start from a different number, you can provide this:
istart = 3
istop = 15
for i in range(istart, istop):
    print(i)Notice that the counting starts with istart, and finishes with istop-1. We can also count in increments of istep:
istart = 3
istop = 15
istep = 4
for i in range(istart, istop, istep):
    print(i)This will print istart, istart + istep, istart + 2*istep etc, but not any value equal to or greater than istep.
A loop to calculate \(\pi\)
The value of \(\pi\) can be found via an infinite sum \(\pi = 2 \sum_{k=0}^\infty 2^k (k!)^2 / (2k+1)!\), where \(n!\) denotes the factorial of \(n\), i.e., \(n! = n(n-1)(n-2)\ldots 1\). This can be computed by initialising a variable to contain the value 1, and then looping through the integers up to n multiplying the variable by each.
enumerations
Often, we may need to iterate through a collection of objects (such as a list), but also keep a count of how many objects we have dealt with.
There are various ways this could be done - one might be:
a = [3, 5, 7]
for i in range(len(a)):
    print("Object number", i, " is ", a[i])However, Python provides the enumerate function for precisely this purpose:
a = [3, 5, 7]
for i, ai in enumerate(a):
    print("Object number", i, " is ", ai)The iterable created by enumerate returns a tuple of (index, object) pairs, which can be assigned to a pair of variables (here, i and ai).
zip
Another common circumstance is that we have two (or more) collections, and we want to access the \(i\)-th element of each simultaneously. Again, this could be achieved using something like:
a = [3, 5, 7]
b = ['a', 'b', 'c']
for i in range(len(a)):
    print("The letter associated with ", a[i], " is ", b[i])but Python also provides the zip function for this purpose:
a = [3, 5, 7]
b = ['a', 'b', 'c']
for ai, bi in zip(a, b):
    print("The letter associated with ", ai, " is ", bi)This creates an iterator which returns a tuple on each iteration, containing the \(i\)-th element of each of the collections passed to zip. The elements of this tuple can be assigned to variables (here, ai and bi).
Now, you start crossing out numbers. First, we consider the first entry in the list, 2. We keep this, but cross out every second number thereafter:
2 3 X 5 X 7 X 9 X 11 X 13 X 15 X 17 X 19 X 21 X 23 X 25
^Start hereWe move our pointer to the next not-crossed-out number, 3. We then cross out every 3rd entry (counting ones that are already crossed out):
2 3 X 5 X 7 X X X 11 X 13 X X X 17 X 19 X X X 23 X 25
  ^Start hereThe next not-crossed out number is 5, so we remove every 5th entry:
2 3 X 5 X 7 X X X 11 X 13 X X X 17 X 19 X X X 23 X X
      ^Start hereIf we continue this procedure, we will find that we do not cross out any more numbers. The remaining numbers - 2, 3, 5, 7, 11, 13, 17, 19 and 23 - are all the primes less than (or equal to) 25.
