Lecture 12 — Controlling Loops ================================= Overview -------- - We will see how to control both for and while loops with - ``break``, ``continue`` - We will see different range functions - We will write many example programs Reading: *Practical Programming*, rest of Chapter 7. Part 1: The Basics ------------------ - ``for`` loops tend to have a fixed number of iterations computed at the start of the loop - ``while`` loops tend to have an indefinite termination, determined by the conditions of the data - Most Python ``for`` loops are easily rewritten as ``while`` loops, but not vice-versa. - In other programming languages, ``for`` and ``while`` are almost interchangeable, at least in principle. Part 1: Ranges -------------- - A range is a function to generate a list of integers. For example, :: >>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - Notice this is up through and **not including** the last value specified! - If we want to start with something other than 0, we provide the starting values :: >>> range(3,8) [3, 4, 5, 6, 7] - We can create increments. For example, :: >>> range(4,20,3) [4, 7, 10, 13, 16, 19] starts at 4, increments by 3, stops when 20 is reached or surpassed. - We can create backwards increments :: >>> range(-1, -10, -1) [-1, -2, -3, -4, -5, -6, -7, -8, -9] Using Ranges in For Loops ------------------------- - We can use the ``range`` to generate the list of values in a for loop. Our first example is printing the contents of the ``planets`` list :: planets = [ 'Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto' ] for i in range(len(planets)): print planets[i] - The variable ``i`` is variously known as the index or the loop index variable or the subscript. - We will modify the loop in class to do the following: - Print the indices of the planets (starting at 1!) - Print the planets backward. - Print every other planet. Loops That Do Not Iterate Over All Indices ------------------------------------------ - Sometimes the loop index should not go over the entire range of indices, and we need to think about where to stop it early, as the next example shows. - Example: Returning to our example from Lecture 1, we will briefly re-examine our solution to the following problem: Given a string, how can we write a function that decides if it has three consecutive double letters? :: def has_three_doubles(s): for i in range(0, len(s)-5): if s[i] == s[i+1] and s[i+2] == s[i+3] and s[i+4] == s[i+5]: return True return False - We have to think carefully about where to start our looping and where to stop! Part 1 Exercises ---------------- #. Generate a range for the positive integers less than 100. Use this to calculate the sum of these values, with and without a for loop. #. Use a range and a for loop to print the even numbers less than a given integer ``n``. #. Suppose we want a list of the squares of the digits 0..9. The following does NOT work :: squares = range(10) for s in squares: s = s*s Why not? Write a different for loop that uses indexing into the ``squares`` list to accomplish our goal. #. The following code for finding out if a word has two consecutive double letters is wrong. Why? When, specifically, does it fail? :: def has_two_doubles(s): for i in range(0, len(s)-5): if s[i] == s[i+1] and s[i+2] == s[i+3]: return True return False #. A local maximum, or peak, in a list is a value that is larger than the values next to it. For example, :: L = [ 10, 3, 4, 9, 19, 12, 15, 18, 15, 11, 14 ] has local maxima at indices 4 and 7. (Note that the beginning and end values are not considered local maxima.) Write code to print the index and the value of each local maximum. Part 2: Nested Loops ------------------------ - Some problems require iterating over either - two dimensions of data, or - all pairs of values from a list - As an example, here is code to print all of the products of digits: :: digits = range(10) for i in digits: for j in digits: print "%d x %d = %d" %(i,j,i*j) - How does this work? - for each value of i the variable in the first, or "outer", loop, - Python executes the *entire* second, or "inner", loop - We will look at finding the two closest points in a list. Example: Finding the Two Closest Points --------------------------------------- - Suppose we are given a list of point locations in two dimensions, where each point is a tuple. For example, :: points = [ (1,5), (13.5, 9), (10, 5), (8, 2), (16,3) ] - Our problem is to find the two points that are closest to each other. - The natural idea is to compute the distance between any two points and find the minimum. - We can do this with and without using a list of distances. - Let's work through the approach to this and post the result on the Piazza site. Exercise: Nested vs. Sequential Loops ------------------------------------- #. The following simple exercise will help you understand loops better. Show the output of each of the following pairs of ``for`` loops. The first two pairs are nested loops, and the third pair is formed by consecutive, or sequential, loops. :: # Version 1 sum = 0 for i in range(10): for j in range(10): sum += 1 print sum :: # Version 2 sum = 0 for i in range(10): for j in range(i+1,10): sum += 1 print sum :: # Version 3 sum = 0 for i in range(10): sum += 1 for j in range(10): sum += 1 print sum Exercise: Modifying Images --------------------------- - It is possible to access the individual pixels in an image as a two dimensional array. This is similar to a list of lists, but is written slightly differently: we use ``pix[i,j]`` instead of ``pix[i][j]`` to access a point at location ``(i,j)`` of the image. - Here is a code that copies one image to another, pixel by pixel. :: from PIL import Image im = Image.open("bolt.jpg") w,h = im.size newim = Image.new("RGB", (w,h), "white") pix = im.load() ## creates an array of pixels that can be modified newpix = newim.load() ## creates an array of pixels that can be modified for i in range(0,w): for j in range(0,h): newpix[i,j] = pix[i,j] newim.show() - Modify the above code so that: - The image is flipped left to right - The image is flipped top to bottom - You introduce a black line of size 10 pixels in the middle of the image horizontally and vertically. - Now, scramble the image by shifting the four quadrants of the image clockwise. - If you want some additional challenge, try these: - Pixellate the image, but taking any block of 8 pixels and replacing all the pixels by their average r,g,b value. Part 3: Controlling Execution of Loops -------------------------------------- - We can control while loops through use of - ``break`` - ``continue`` - We need to be careful to avoid infinite loops Using a Break ------------- - We can terminate a loop immediately upon seeing the 0 using Pythons ``break``: :: sum = 0 while True: x = int( raw_input("Enter an integer to add (0 to end) ==> ")) if x == 0: break sum += x print sum - ``break`` sends the flow of control immediately to the first line of code outside the current loop, and - The while condition of ``True`` essentially means that the only way to stop the loop is when the condition that triggers the ``break`` is met. Continue: Skipping the Rest of a Loop ------------------------------------- - Suppose we want to skip over negative entries in a list. We can do this by telling Python to ``continue`` when it sees a blank line: :: for item in mylist: if item < 0: continue print item - When it sees ``continue``, Python immediate goes back to the ``while`` condition and re-evaluates it, skipping the rest of the loop. - Any loop that uses ``break`` or ``continue`` can be rewritten without either of these. - Therefore, we choose to use them only if they make our code clearer. - A loop with more than one continue or more than one break is often unclear! - This particular example is probably better without the ``continue``. - Usually when we use ``continue`` the rest of the loop would be much longer, with the condition that triggers the ``continue`` tested right at the time preferably at the top of the loop. Part 3 Exercises ---------------- #. Given two lists ``L1`` and ``L2`` measuring the daily weights (floats) of two rats write a ``while`` loop to find the first day that the weight of rat 1 is greater than that of rat 2. #. Do either of the following examples cause an infinite loop? :: import math x = float(raw_input("Enter a positive number -> ")) while x > 1: x = math.sqrt(x) print x :: import math x = float(raw_input("Enter a positive number -> ")) while x >= 1: x = math.sqrt(x) print x Summary ------- - ``range`` is used to generate a list of indices in a ``for`` loop. - At each iteration of a ``for`` loop, a value from a list is copied to a variable automatically. Do not change this value yourself. - While loops are needed especially when the termination conditions must be determined during the loop's computation. - Both for loops and while loops may be controlled using break and continue, but don't overuse these. - While loops may become "infinite" - Use a debugger to understand the behavior of your program and to find errors.