First Summer 2009

Thursday, June 10, 2010
Today in lecture and lab we review the material for tomorrow's exam:

Solutions have been posted on Class Notes under tomorrow's date.

Also, here are the notes from today's lab:

Knowing that m = {} initializes a dictionary and
m[2, 3] = 4 assigns a value of 4 to the entry with key (2, 3)
write code such that:

(a) m is a dictionary that stores the magic square of size 3
m = {}
m['columns'] = 3
m['rows'] = 3
m[2, 1] = 1
m[0, 2] = 2
m[1, 0] = 3
m[0, 0] = 4
m[1, 1] = 5
m[2, 2] = 6
m[1, 2] = 7
m[2, 0] = 8
m[0, 1] = 9

m = [[1, 2, 3], [3, 4, 2], [1, 2, 9]]

size = len(m)

for row in m:
  for elem in row:
    print elem,
  print 

for i in range(len(m)):
  for j in range(len(m[i])):
    print m[i][j], 
  print 

(b) show(m) is a function of one argument (a magic square) that prints it
def show(m):
  for i in range(m['rows']):
    for j in range(m['columns']):
      print m[i, j],
    print

(c) generate(n) produces an nxn matrix with random integers in it, as a 
dictionary; test it with show(generate(5)) If the random numbers in your
matrix are between 0 and 999 how can you print the matrix so the columns
are properly lined up? How can you be sure of this format in general? 

  1 346   9
102   8   8
 12 481 490

 1 346 9
102 8 8
12 481 490

Here's generate together with the solution for the magic square problem:

def show(m):
  for i in range(m['rows']):
    for j in range(m['columns']):
      print "%3s" % m[i, j],
    print

m = {}
m['columns'] = 3
m['rows'] = 3
m[2, 1] = 1
m[0, 2] = 2
m[1, 0] = 3
m[0, 0] = 4
m[1, 1] = 5
m[2, 2] = 6
m[1, 2] = 7
m[2, 0] = 8
m[0, 1] = 9

show(m)

def generate(n):
    import random
    m = {}
    m['rows'] = n
    m['columns'] = n
    for i in range(n):
        for j in range(n):
            m[i, j] = random.randrange(1000)
    return m

def magic(size):
    size = 2 * size + 1
    m = {}
    m['rows'] = size
    m['columns'] = size
    for i in range(size):
        for j in range(size):
            m[i, j] = 0
    k = 1
    i = size - 1
    j = size / 2
    m[i, j] = k
    for k in range(2, size*size+1):
        if m[(i+1)%size, (j+1)%size] == 0:
            (i, j) = ((i+1)%size, (j+1)%size)
        else:
            (i, j) = (i-1, j)
        m[i, j] = k
        show(m)
        print "-" * 35
    return m

We also looked at this program:

class Person(object):
    def __init__(self, name, initial):
        self.name = name
        self.scores = [ initial ]
    def add(self, score):
        self.scores.append(score)
    def report(self):
        return "Hi I'm", self.name, "and my scores are", self.scores, "for a total of", self.total()
    def lessThan(self, other):
        return self.total() < other.total()
    def total(self):
        result = 0
        for score in self.scores:
            result += int(score)
        return result

def summary(filename):
    file = open(filename, "r")
    lines = file.readlines()
    file.close()
    d = {}
    for line in lines:
        (name, value) = line.split()
        if (d.has_key(name)):
            d[name].add(value)
        else:
            d[name] = Person(name, value)
    return d

def report(data):
    objects = data.values()
    objects.sort(cmp=lambda x, y: y.total() - x.total())
    for object in objects:
        print object.report()
    
report(summary("data.txt"))

We tried it on this file (data.txt):

Spongebob -2
Squidward 12
Mr.Krabs 4
Spongebob 10
Spongebob 8
Mr.Krabs -13
Plankton 7
Squidward 3

Note that total() hides the criterion used for sorting (sum or average). 

Also .sort(...) for any list (here -- of objects) is completely customizable.

We can pass cmp=... where the right hand side is a closure (lambda expression).

The lambda expression has two arguments and decides whether their current order is good or bad.

A negative value returned by the lambda expression indicates the elements are in the wrong order.


Updated by Adrian German for A201/A597