Loops and Lists
2.3 Alternative Implementations with Lists and Loops
62 2 Loops and Lists
Cdegrees = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
print ’ C F’
for C in Cdegrees:
F = (9.0/5)*C + 32
print ’%5d %5.1f’ % (C, F)
This code is found in the filec2f_table_list.pyand its output becomes
C F
-20 -4.0 -15 5.0 -10 14.0 -5 23.0 0 32.0 5 41.0 10 50.0 15 59.0 20 68.0 25 77.0 30 86.0 35 95.0 40 104.0
Cdegrees = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
index = 0
print ’ C F’
while index < len(Cdegrees):
C = Cdegrees[index]
F = (9.0/5)*C + 32
print ’%5d %5.1f’ % (C, F) index += 1
2.3.2 The Range Construction
It is tedious to write the many elements in theCdegreesin the previous programs.
We should use a loop to automate the construction of theCdegreeslist. Therange construction is particularly useful in this regard:
range(n)generates integers0, 1, 2, ..., n-1.
range(start, stop, step) generates a sequence if integers start, start+step,start+2*step, and so on up to, but not including,stop. For example,range(2, 8, 3)returns 2 and 5 (and not 8), whilerange(1, 11, 2)returns 1, 3, 5, 7, 9.
range(start, stop)is the same asrange(start, stop, 1). Aforloop over integers are written as
for i in range(start, stop, step):
...
We can use this construction to create aCdegreeslist of the values20;15; : : : ; 40:
Cdegrees = []
for C in range(-20, 45, 5):
Cdegrees.append(C)
# or just
Cdegrees = range(-20, 45, 5)
Note that the upper limit must be greater than40to ensure that40is included in the range of integers.
Suppose we want to createCdegreesas10;7:5;5; : : : ; 40. This time we cannot userangedirectly, becauserangecan only create integers and we have decimal degrees such as7:5and1:5. In this more general case, we introduce an integer counteriand generate theC values by the formulaC D 10Ci2:5for iD0; 1; : : : ; 20. The following Python code implements this task:
Cdegrees = []
for i in range(0, 21):
C = -10 + i*2.5 Cdegrees.append(C)
64 2 Loops and Lists
2.3.3 For Loops with List Indices
Instead of iterating over a list directly with the construction
for element in somelist:
...
we can equivalently iterate of the list indices and index the list inside the loop:
for i in range(len(somelist)):
element = somelist[i]
...
Sincelen(somelist)returns the length ofsomelistand the largest legal index islen(somelist)-1, because indices always start at 0,range(len(somelist)) will generate all the correct indices:0,1,: : :,len(somelist)-1.
Programmers coming from other languages, such as Fortran, C, C++, Java, and C#, are very much used to forloops with integer counters and usually tend to usefor i in range(len(somelist))and work withsomelist[i]inside the loop. This might be necessary or convenient, but if possible, Python programmers are encouraged to usefor element in somelist, which is more elegant to read.
Iterating over loop indices is useful when we need to process two lists simul- taneously. As an example, we first create twoCdegreesandFdegreeslists, and then we make a list to write out a table withCdegreesandFdegreesas the two columns of the table. Iterating over a loop index is convenient in the final list:
Cdegrees = []
n = 21 C_min = -10 C_max = 40
dC = (C_max - C_min)/float(n-1) # increment in C for i in range(0, n):
C = -10 + i*dC Cdegrees.append(C) Fdegrees = []
for C in Cdegrees:
F = (9.0/5)*C + 32 Fdegrees.append(F)
for i in range(len(Cdegrees)):
C = Cdegrees[i]
F = Fdegrees[i]
print ’%5.1f %5.1f’ % (C, F)
Instead of appending new elements to the lists, we can start with lists of the right size, containing zeros, and then index the lists to fill in the right values. Creating a list of lengthnconsisting of zeros (for instance) is done by
somelist = [0]*n
With this construction, the program above can useforloops over indices every- where:
n = 21 C_min = -10 C_max = 40
dC = (C_max - C_min)/float(n-1) # increment in C Cdegrees = [0]*n
for i in range(len(Cdegrees)):
Cdegrees[i] = -10 + i*dC Fdegrees = [0]*n
for i in range(len(Cdegrees)):
Fdegrees[i] = (9.0/5)*Cdegrees[i] + 32 for i in range(len(Cdegrees)):
print ’%5.1f %5.1f’ % (Cdegrees[i], Fdegrees[i])
Note that we need the construction[0]*nto create a list of the right length, other- wise the index[i]will be illegal.
2.3.4 Changing List Elements
We have two seemingly alternative ways to traverse a list, either a loop over ele- ments or over indices. Suppose we want to change theCdegreeslist by adding 5 to all elements. We could try
for c in Cdegrees:
c += 5
but this loop leavesCdegreesunchanged, while
for i in range(len(Cdegrees)):
Cdegrees[i] += 5
works as intended. What is wrong with the first loop? The problem is thatcis an ordinary variable, which refers to a list element in the loop, but when we executec += 5, we letcrefer to a newfloatobject (c+5). This object is never inserted in the list. The first two passes of the loop are equivalent to
c = Cdegrees[0] # automatically done in the for statement c += 5
c = Cdegrees[1] # automatically done in the for statement c += 5
The variableccan only be used to read list elements and never to change them.
Only an assignment of the form
66 2 Loops and Lists
Cdegrees[i] = ...
can change a list element.
There is a way of traversing a list where we get both the index and an element in each pass of the loop:
for i, c in enumerate(Cdegrees):
Cdegrees[i] = c + 5
This loop also adds 5 to all elements in the list.
2.3.5 List Comprehension
Because running through a list and for each element creating a new element in another list is a frequently encountered task, Python has a special compact syntax for doing this, calledlist comprehension. The general syntax reads
newlist = [E(e) for e in list]
whereE(e)represents an expression involving elemente. Here are three examples:
Cdegrees = [-5 + i*0.5 for i in range(n)]
Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees]
C_plus_5 = [C+5 for C in Cdegrees]
List comprehensions are recognized as aforloop inside square brackets and will be frequently exemplified throughout the book.
2.3.6 Traversing Multiple Lists Simultaneously
We may use theCdegreesandFdegreeslists to make a table. To this end, we need to traverse both arrays. Thefor element in listconstruction is not suitable in this case, since it extracts elements from one list only. A solution is to use afor loop over the integer indices so that we can index both lists:
for i in range(len(Cdegrees)):
print ’%5d %5.1f’ % (Cdegrees[i], Fdegrees[i])
It happens quite frequently that two or more lists need to be traversed simultane- ously. As an alternative to the loop over indices, Python offers a special nice syntax that can be sketched as
for e1, e2, e3, ... in zip(list1, list2, list3, ...):
# work with element e1 from list1, element e2 from list2,
# element e3 from list3, etc.
Thezipfunction turnsnlists (list1, list2, list3, ...) into one list ofn- tuples, where eachn-tuple(e1,e2,e3,...) has its first element (e1) from the first list (list1), the second element (e2) from the second list (list2), and so forth. The loop stops when the end of the shortest list is reached. In our specific case of iterating over the two listsCdegreesandFdegrees, we can use thezip function:
for C, F in zip(Cdegrees, Fdegrees):
print ’%5d %5.1f’ % (C, F)
It is considered morePythonicto iterate over list elements, hereCandF, rather than over list indices as in thefor i in range(len(Cdegrees))construction.