Computer Science 15-112, Spring 2012
Class Notes:  Loops


  1. Required Reading
  2. "for" loop over a range
    1. Range from 0 to y:  use xrange(y+1)
    2. Range from x to y:  use xrange(x, y+1)
    3. Range from x to y with step z:  use xrange(x, y+1, z)
    4. Range in reverse (use a negative step)
    5. xrange versus range
  3. Nested "for" loops
  4. The "while" statement
  5. Examples of "while" Loops
    1. Read Until a Sentinel
    2. Read Until a Condition
    3. Find the Nth Positive Integer with Some Property
    4. Misuse:  Iterate Over a Range of Integers
  6. break and continue
  7. Infinite "while" loop with break
  8. Practice Problems
    1. Tracing
    2. Mystery Method(s)
    3. Sum the numbers from 1 to N
    4. Sum the odd numbers from 1 to N
      1. Using "if"
      2. Using a different increment
    5. Sum the first N odd numbers
    6. isPrime
    7. fasterIsPrime
    8. nthPrime

Loops

  1. Required Reading
    1. Python Language Reference, Ch 7.2 (The while statement)
    2. Python Language Reference, Ch 7.3 (The for statement)
      Think of the targetList as a single variable.  Plus, you may ignore the note on the subtlety.
    3. The Python Tutorial, Ch 4.2-4.5
       
  2. "for" loop over a range
    1. Range from 0 to y:  use xrange(y+1)

      # print the numbers from 0 to 4 (not 5)
      for x in xrange(5):
          print x


    2. Range from x to y:  use xrange(x, y+1)

      # print the numbers from 10 to 14 (not 15)
      for x in xrange(10, 15):
          print x


    3. Range from x to y with step z:  use xrange(x, y+1, z)

      # print the even numbers from 10 to 14 (not 15)
      for x in xrange(10, 15, 2):
          print x


    4. Range in reverse (use a negative step):

      # print the even numbers from 14 to 10 (not 9)
      for x in xrange(14, 9, -2):
          print x

       
    5. xrange versus range:

      # xrange is usually a little more efficient
      # xrange may work on larger ranges without running out of memory

      # range creates an actual list (which we will learn about next week)

  3. Nested "for" loops

    n = int(raw_input("How many rows? "))
    for row in xrange(n):
        for col in xrange(row+1):
            print "*",
        print


  4. The "while" statement

    while (test):
        body

    For example:

    def powersOfTwo(upperLimit):
        n = 1
        while (n < upperLimit):
            print n
            n *= 2
        print "After loop, n = ", n

    And a similar example:

    def dividingByTwo(n):
        count = 0
        while (n > 0):
            print n
            n /= 2
            count += 1
        print "After loop, n=", n, " and count=", count

     
  5. Examples of "while" Loops
     
    1. Read Until a Sentinel

      # Keep reading names until the user enters "done"
      count = 0
      sentinel = "done"
      input = None
      print "Keep entering names.  To quit, enter", sentinel
      while (input != sentinel):
          input = raw_input("Enter name #" + str(count+1) + ": ")
          if (input != sentinel):
              count += 1
      print "You entered", count, "names!"

       
    2. Read Until a Condition

      # keep reading numbers until their sum exceeds 10
      sum = 0.0
      while (sum < 10):
          print "Sum = " + str(sum) + ". ",
          input = float(raw_input("Next number --> "))
          sum += input
      print "Final sum = ", sum

       
    3. Find the Nth Positive Integer with Some Property

      # find the nth number that is a multiple of either 4 or 7

      def isMultipleOf4Or7(x):
          return ((x % 4) == 0) or ((x % 7) == 0)

      def nthMultipleOf4Or7(n):
          found = 0
          guess = -1
          while (found <= n):
              guess += 1
              if (isMultipleOf4Or7(guess)):
                  found += 1
          return guess

      input = None
      while (input != -1):
          input = int(raw_input("Enter a # (or -1 to quit): "))
          if (input != -1):
              print "   nthMultipleOf4Or7(", input, ") =", nthMultipleOf4Or7(input)
      print "Bye!"

       
    4. Misuse:  Iterate Over a Range of Integers

      # sum numbers from 1 to 10
      # note:  this works, but you should not use "while" here.
      #        instead, do this with "for" (once you know how)
      sum = 0
      counter = 1
      while (counter <= 10):
          sum += counter
          counter += 1
      print "The sum from 1 to 10 is", sum

      Once again, but with a bug!:

      # sum numbers from 1 to 10
      # warning: buggy version!
      sum = 0
      counter = 0
      while (counter <= 10):
          counter += 1
          sum += counter
      print "The sum from 1 to 10 is", sum


      And once more, using a "for" loop (the right way!):


      # sum numbers from 1 to 10
      sum = 0
      for counter in xrange(1,11):
          sum += counter
      print "The sum from 1 to 10 is", sum
       
  6. break and continue

    for n in xrange(20):
        if (n % 3 == 0):
            continue # skips rest of this pass
        elif (n == 10):
            break # skips rest of entire loop
        print n # prints 1, 2, 4, 5, 7, 8 (skips 3, 6, 9, then breaks)

     
  7. Infinite "while" loop with break

    while (True):
        response = raw_input("Enter a string (or 'done' to quit): ")
        if (response == "done"):
            break
        print "  You entered: ", response
    print "Bye!"

  8. Practice Problems
    1. Tracing

      # trace this code by hand, then run it to confirm your prediction
      x = 13
      y = 1
      while (y < x):
          print x,y
          x -= 2
          y += 3
      print x,y
       
    2. Mystery Method(s)

      # State what this function does, in just a few words of plain English.
      # Do not state line-by-line what it does at a low level.  Find the general pattern.
      # Also note that there is a clearer, faster, better way to do the same thing!

      def mysteryA(x, y):
          # assume x and y are non-negative integers
          c = 0
          while (x > 0):
              c += y
              x -= 1
          return c

       
    3. Sum the numbers from 1 to N

      def sumFrom1ToN(n):
          sum = 0
          for i in xrange(n+1):
              sum += i
          return sum

      # let's see it in action...
      for n in xrange(-2,6):
          print n, sumFrom1ToN(n)

    4. Sum the odd numbers from 1 to N
      1. Using "if"

        def sumOddsFrom1ToN(n):
            sum = 0
            for i in xrange(n+1):
                if (i % 2 == 1):
                    sum += i
            return sum

        # let's see it in action...
        for n in xrange(-2,6):
            print n, sumOddsFrom1ToN(n)

      2. Using a different increment

        def sumOddsFrom1ToN(n):
            sum = 0
            for i in xrange(1, n+1, 2):
                sum += i
            return sum

        # let's see it in action...
        for n in xrange(-2,6):
            print n, sumOddsFrom1ToN(n)


    5. Sum the first N odd numbers

      def sumOfFirstNOdds(n):
          sum = 0
          for i in xrange(n):
              sum += 2*i+1
          return sum

      # let's see it in action...
      for n in xrange(6):
          print n, sumOfFirstNOdds(n)

      Or...

      def sumOfFirstNOdds(n):
          sum = 0
          for i in xrange(1,2*n+1,2):
              sum += i
          return sum

      Or...

      def sumOfFirstNOdds(n):
          sum = 0
          nextOdd = 1
          for i in xrange(n):
              sum += nextOdd
              nextOdd += 2
          return sum

      Once more, this time with a bug...

      def sumOfFirstNOdds(n):  # This version has a bug!
          sum = 0
          for i in xrange(n):
              sum += 2*n+1
          return sum

    6. isPrime

      #Note: there are faster/better ways.  We're just going for clarity and simplicity here.
      def isPrime(n):
          if (n < 2):
              return False
          for factor in xrange(2,n):
              if (n % factor == 0):
                  return False
          return True

      # And take it for a spin
      for n in xrange(500):
          if isPrime(n):
              print n,

    7. fasterIsPrime

      #Note: this is still not the fastest way, but it's a nice improvement.
      def fasterIsPrime(n):
          if (n < 2):
              return False
          if (n == 2):
              return True
          if (n % 2 == 0):
              return False
          maxFactor = int(round(n**0.5))
          for factor in xrange(2,maxFactor+1):
              if (n % factor == 0):
                  return False
          return True

      # Verify these are the same
      for n in xrange(1000):
          if (isPrime(n) != fasterIsPrime(n)): print n
          assert(isPrime(n) == fasterIsPrime(n))
      print "They seem to work the same!"

      # Now let's see if we really sped things up
      import time
      bigPrime = 499 # Try 1010809, or 10101023, or 102030407
      print "Timing isPrime(",bigPrime,")",
      time0 = time.time()
      print ", returns ", isPrime(bigPrime),
      time1 = time.time()
      print ", time = ",(time1-time0)*1000,"ms"

      print "Timing fasterIsPrime(",bigPrime,")",
      time0 = time.time()
      print ", returns ", fasterIsPrime(bigPrime),
      time1 = time.time()
      print ", time = ",(time1-time0)*1000,"ms"

    8. nthPrime

      def nthPrime(n):
          found = 0
          guess = 0
          while (found <= n):
              guess += 1
              if (isPrime(guess)):
                  found += 1
          return guess

      # and let's see a list of the primes
      for n in xrange(10):
          print n, nthPrime(n)


carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem   -   carpe diem