Week 2: for loops, accumulator

Monday

for loops

The general syntax of a for loop is this:

for variable in sequence:
    do this
    and this
    and as many lines as are indented

Here’s an example from last time:

$ python3 times.py
What factor? 4
1 x 4 = 4
2 x 4 = 8
3 x 4 = 12
4 x 4 = 16
5 x 4 = 20
6 x 4 = 24
7 x 4 = 28
8 x 4 = 32
9 x 4 = 36
10 x 4 = 40
11 x 4 = 44
12 x 4 = 48

We could do this with lots of (12) print statements, but that won’t scale well if we want to keep going (13x4, 14x4, and so on…​).

Here’s the above code written using a for loop:

    factor = int(input("What factor? "))
    for num in range(1,13):
        answer = num * factor
        print(num,"x",factor,"=",answer)

First we get the input from the user and convert it to an integer. Next we start the for loop with the variable num. In this loop num is first set to 1, then the code block (the two indented lines) is executed. Then num is set to 2 and the code block is run again, then num is set to 3, and so on…​.

The range(1,13) function is an easy way to make a sequence of numbers from 1 to 12.

the range() function

Technically range() can take up to three arguments: range(start,stop,step). Here are some examples using three arguments. Can you figure out what each argument represents?

>>> for i in range(1,11,2):
...    print(i)
...
1
3
5
7
9
>>> for i in range(50,0,-5):
...    print(i)
...
50
45
40
35
30
25
20
15
10
5

If you just call range(10), with only one argument, it uses a default start of 0 and a default step of 1:

>>> for i in range(10):
...    print(i)
...
0
1
2
3
4
5
6
7
8
9

for loop puzzles!

P1: can you write this program?

$ python3 puzzle1.py
how many? 7
XXXXXXX
XXXXXXX
XXXXXXX
XXXXXXX
XXXXXXX
XXXXXXX
XXXXXXX

$ python3 puzzle1.py
how many? 3
XXX
XXX
XXX

P2: how about this program?

$ python3 puzzle2.py
number: 4
X
XX
XXX
XXXX

$ python3 puzzle2.py
number: 7
X
XX
XXX
XXXX
XXXXX
XXXXXX
XXXXXXX

Here’s the source code for the above puzzle2 problem:

def main():
    ch = "X"
    number = int(input("number: "))
    for i in range(number):
        print((i+1)*ch)

main()

P3: Can you write this program?

$ python3 puzzle2.py
number: 4
XXXX
XXX
XX
X

$ python3 puzzle2.py
number: 7
XXXXXXX
XXXXXX
XXXXX
XXXX
XXX
XX
X

P4: still more???!?!

$ python3 puzzle4.py
number: 4
1
22
333
4444

$ python3 puzzle4.py
number: 8
1
22
333
4444
55555
666666
7777777
88888888

P5: last one!

$ python3 puzzle5.py
number: 5
    X
   XX
  XXX
 XXXX
XXXXX
$ python3 puzzle5.py
number: 7
      X
     XX
    XXX
   XXXX
  XXXXX
 XXXXXX
XXXXXXX

Wednesday

Here’s the source code for puzzle 4 above:

def main():
    number = int(input("number: "))
    for i in range(number):
        n = i+1
        print(n*str(n))

main()

The n*str(n) part will print two 2’s if n=2, and five 5’s if n=5.

temperature tables

Here’s how to convert temperatures from Fahrenheit to Celsius: c = (f - 32)/1.8 Given that, can you write a program to show a table of temperatures from 0 to 100F, going by 10s?

$ python3 f2c.py
0 F is -17.77777777777778 C
10 F is -12.222222222222221 C
20 F is -6.666666666666666 C
30 F is -1.1111111111111112 C
40 F is 4.444444444444445 C
50 F is 10.0 C
60 F is 15.555555555555555 C
70 F is 21.11111111111111 C
80 F is 26.666666666666664 C
90 F is 32.22222222222222 C
100 F is 37.77777777777778 C

Hopefully you see that’s just a simple for loop, using a range of values for the Fahrenheit temperature. Here’s the code (just the loop):

    for f in range(0,101,10):
        c = (f - 32)/1.8
        print(f,"F is", c, "C")

accumulator pattern

How about this one? Can you get the starting temperature and the "step" from the user, and display a table of ten values?

$ python3 moretemps.py
starting temp F? 12
           step? 3.5

1 12.0 F  --  -11.11111111111111 C
2 15.5 F  --  -9.166666666666666 C
3 19.0 F  --  -7.222222222222222 C
4 22.5 F  --  -5.277777777777778 C
5 26.0 F  --  -3.333333333333333 C
6 29.5 F  --  -1.3888888888888888 C
7 33.0 F  --  0.5555555555555556 C
8 36.5 F  --  2.5 C
9 40.0 F  --  4.444444444444445 C
10 43.5 F  --  6.388888888888888 C

One way to do this is with an accumulator variable. You start with f equal to the user’s starting temperature, then each time through the loop you add to it. To do something like this we will use this line of code:

f = f + step

That may look odd to you (it’s not a math equation!), but it works. Here’s a simpler example:

>>> x = 0
>>> print(x)
0
>>> x = x + 1
>>> print(x)
1
>>> for i in range(5):
...     x = x + 1
...     print(x)
...
2
3
4
5
6

In the above example we start with x at some value (here zero), then add to it with x = x + 1. This code is done from right to left, so the right side happens first: look up the value stored in x, add 1 to that value to create a new value. After that the assignment (=) happens: assign the new value to the variable on the left. It just happens that we store the new value back in the same place as the old value (i.e., the old value is overwritten).

This notation (x = x + 1) is used so often that there’s a python shortcut for it: x += 1.

Back to the temperature table where the user specifies the start temperature and the step, we can do that with an accumulator variable:

    start = float(input("starting temp F? "))
    step  = float(input("           step? "))
    f = start
    for i in range(10):
        c = (f - 32)/1.8              # calculate temp in C
        print(i+1,f,"F  -- ",c,"C")   # output results
        f = f + step                  # update f for next pass through the loop

Your turn!

Can you write this program: ask the user for the number of students, then ask for the quiz grade for each student. At the end, output the average quiz grade for the whole class:

$ python3 grades.py
how many students? 6
quiz grade: 80
quiz grade: 99
quiz grade: 75
quiz grade: 83
quiz grade: 92
quiz grade: 77
The ave quiz grade is: 84.33333333333333

$ python3 grades.py
how many students? 4
quiz grade: 1
quiz grade: 2
quiz grade: 3
quiz grade: 4
The ave quiz grade is: 2.5

Friday

What does this program do?

n = int(input("n: "))
x = 1
for i in range(2,n):
    x = x * i
print(x)

It’s hard to say, since there’s no comment at the top, and the variable names aren’t that descriptive.

What does this program do?

"""
Calculate the Gamma function of n, where

   Gamma(n) = (n - 1)! = (n-1)*(n-2)*...*2*1

J. Knerr
Spring 2011
"""

def main():
    """get n, calculate G(n), output results"""

    print("Gamma(n) calculator...please enter n\n")

    n = int(input("n: "))
    result = 1
    for i in range(2,n):
        result = result * i         # ACCUMULATOR!!!

    print("Gamma(",n,") =", result)


main()

They actually both do the same thing, but the second one is much easier to read.

Also note, it’s using something like an accumulator. This one is computing 1*2*3*…​(n-2)*(n-1) for some given number n. Since it is using multiplication, the starting number (result = 1) isn’t zero. Not all accumulators start at zero.

indexing and len()

Indexing is how we pick out a specific character from a string, or a specific item from a list.

A string is a sequence of characters between single or double quotes. A list is a sequence of items, where each item could be anything (an integer, a float, a string, etc).

Both strings and lists have lengths: a string’s length is the number of characters in the string; a list’s length is the number of items in the list.

>>> S = "hello"
>>> L = ["a","b","zebra"]
>>> len(S)
5
>>> len(L)
3

Each character in a string as well as each item in a list has a position, also called an index. In python, positions start at 0, so the "h" in the above string is at position 0, and the "o" is at position 4 (note: one less than the length of the string). In the list above, "zebra" is at position 2.

You can access individual characters in a string, or items in a list, using square-bracket indexing:

>>> print(L[2])
zebra
>>> print(S[2])
l
>>> print(S[3])
l
>>> print(S[4])
o

One way to loop over all characters in a string it to combine the range() and len() functions in a for loop:

>>> S = "hello"
>>> for i in range(len(S)):
...    print(i,S[i])
...
0 h
1 e
2 l
3 l
4 o
>>>
>>> L = ["a","b","zebra"]
>>> for i in range(len(L)):
...    print(L[i])
...
a
b
zebra

Note: for S = "hello", it’s length is 5 (len(S) returns 5), but the indices are 0, 1, 2, 3, 4.

string accumulator

How would you write this program?

$ python3 stracc.py
text: hello
h e l l o
$ python3 stracc.py
text: we love comp sci!!
w e   l o v e   c o m p   s c i ! !

So for each text string entered, we accumulate a new string, one character at a time, also adding in a single space after character.

Here’s one way to do this, using a string accumulator:

text = input("text: ")
new = ""
for i in range(len(text)):
    new = new + text[i] + " "
print(new)

Start with an empty string (new), then, for every character in the string, add the next character to new plus a space. After the loop, print out the accumulated string.

reverse a string

How about this one?

$ python3 revstr.py
text: ABCDEFG
      GFEDCBA
$ python3 revstr.py
text: Hello!
      !olleH

Hint: if we did another string accumulator (in a for loop), what’s the difference between these two statements?

new = new + text[i]
new = text[i] + new

One adds the next character to the right side of new, and the other (the second one) adds the next character to the left side.