00 upvotes00 downvotes

1 views8 pagesJul 20, 2014

t3_v2_sol

© © All Rights Reserved

PDF, TXT or read online from Scribd

© All Rights Reserved

1 views

00 upvotes00 downvotes

t3_v2_sol

© All Rights Reserved

You are on page 1of 8

Test 3 Version 2

November 21, 2013

SOLUTIONS

1. (6 points) Given a dictionary, d, whose keys are strings and values are sets of strings. Write one line

of code to create a set, s, that contains all strings that appear in the dictionary both as a key and as

a member of the value sets. No loops are allowed. For example, if the dictionary is

d = { 'rpi' : set(['union', 'wpi']), 'wpi' : set(['union', 'cornell'])}

Then s should be

set(['wpi'])

Solution:

This is problem is ill-formed. It was originally intended to have all keys and values be strings, but it

was mistakenly changed just before the test. If that were the case then the following solution would

have been correct:

s = set(d.keys()) & set(d.values())

It is the solution that most students wrote, although some students did realize that d.values() is a

list of sets (as the problem was written) and therefore creating a set is not a valid operation. There is

a one-line solution to the question as written using functions we have not discussed:

s = set(d.keys()) & reduce(lambda x,y: x.union(y), d.values())

If you are curious, take a look at reduce and lambda to see if you can gure out what these do.

2. (10 points) Consider the following code for binary search, including an added print statement

def binary_search( x, L):

low = 0

high = len(L)

while low != high:

mid = (low+high)/2

print low, mid, high

if x > L[mid]:

low = mid+1

print "above"

else:

high = mid

print "below"

return low

Show the output of the statement

print binary_search( 10, [ 1, 4, 6, 6, 10, 10, 10, 12 ])

Solution:

0 4 8

below

0 2 4

above

3 3 4

above

4

3. (4 points) When running the merge function discussed in lecture, how must the two input lists be

organized in order for the function to work properly?

Solution:

The values in each list must be in increasing order (or at least non-decreasing).

2

4. (24 points, total) Consider the Bird class

class Bird(object):

def __init__( self, n, x0, y0, r0, dx0, dy0 ):

self.name = n

self.x = x0

self.y = y0

self.radius = r0

self.dx = dx0

self.dy = dy0

(a) (9 points out of the 24) Add two methods to the Bird class. The rst one, called move should

change the x and y positions of a bird by the dx and dy values. The second one, called in_bounds,

should return True if all of the birds circle is inside the game rectangle (with corners (0,0) and

(100,100)), and False otherwise.

b = Bird( 'Tweety', 21.5, 12.5, 8, -6.2, -3.2)

b.move()

print b.x, b.y # Should output 15.3 9.3

print b.in_bounds() # Should output True

b.move()

print b.in_bounds() # Should output False

Solution:

def move(self):

self.x += self.dx

self.y += self.dy

def in_bounds(self):

return self.x-self.radius > 0 and self.x+self.radius < 100 and \

self.y-self.radius > 0 and self.y+self.radius < 100

(b) (15 points out of the 24) When you wrote your code for HW 7 we allowed you to assume

(among other things) that the birds were inside the game rectangle at the start. Our solution,

however, included safety checks to make sure that we gave you valid input. Write a function

check_birds that takes a list of birds as its only argument. The function should change the

list of birds to remove any bird having any part of its circle on or outside the boundaries of the

rectangle. The function should return the name of the birds that were removed. For example,

after the following code

birds = []

birds.append( Bird('Tweety', 7, 95, 12, 2, 3) )

birds.append( Bird('Sylvestor', 50, 50, 10, -3, 6) )

birds.append( Bird('Daisy', 80, 20, 9, -1, 5) )

print check_birds(birds), len(birds)

The output should be

[ 'Tweety' ], 2

because Tweety has been removed from birds for being outside the rectangle.

Solution:

def check_birds( birds ):

removed = []

i = 0

while i < len(birds):

if not birds[i].in_bounds():

removed.append( birds[i].name )

3

birds.pop(i)

else:

i += 1

return removed

Solution where the indices of the birds to remove are kept:

def check_birds( birds ):

remove_indices = []

remove_names = []

for i in range(len(birds)):

if not birds[i].in_bounds():

remove_names.append( birds[i].name )

remove_indices.append( i )

remove_indices.reverse() # so we can pop back-to-fron

for i in remove_indices:

birds.pop(i)

return remove_names

Solution where the birds to keep are in the second list that is properly copied back to birds

def check_birds( birds ):

remove_names = []

keep_birds = []

for i in range(len(birds)):

if birds[i].in_bounds():

keep_birds.append(birds[i])

else:

remove_names.append( birds[i].name )

birds[:] = remove_names # The [:] is crucial

return remove_names

4

5. (24 points, total) Suppose you have a dictionary to represent your phone contacts. The keys are the

names of people and the value associated with each key is the set of all that persons phone numbers,

represented as strings (and only three digits for simplicitys sake). Here is an example:

contacts = {}

contacts['Bob'] = set(['100', '909'])

contacts['Alice'] = set(['505', '101'])

contacts['Chad'] = set(['999'])

contacts['Danielle'] = set(['123' ,'234', '345'])

(a) (7 points of the total) Write a function called add_contact that adds a phone number to a

contact. If the contact does not exist, the function should create the contact. For example, the

function call

add_contacts( contacts, 'Bob', '108')

would add a third number to the contact set for 'Bob'

Solution:

def add_contacts( contacts, name, number ):

if name in contacts:

contacts[name].add(number)

else:

contacts[name] = set([number])

(b) (7 points of the total) Write a function find_name that takes the contact dictionary and a

phone number and returns the name of the individual having that number. If the number is not

in the dictionary, the function should return the string "Unknown". For example, the call

find_name( contacts, '234' )

should return 'Danielle'. You may assume each phone number is associated with at most one

contact name.

Solution:

def find_name( contacts, number):

for name in contacts.keys():

if number in contacts[name]:

return name

return 'Unknown'

(c) (10 points of the total) Write a function reverse_contacts that creates and returns a new

dictionary where the keys are phone numbers and the values are the names of the people having

the phone number. You may assume only one person has a given phone number. Using this

new dictionary it will be much faster to search for the name associated with a number. For the

contacts dictionary from the start of the problem the call

reverse_contacts( contacts )

Should produce the dictionary

{'101': 'Alice', '909': 'Bob', '999': 'Chad', '345': 'Danielle', \

'123': 'Danielle', '234': 'Danielle', '100': 'Bob', '505': 'Alice'}

Solution:

5

def reverse_contacts( contacts ):

rc = {}

for name in contacts.keys():

for number in contacts[name]:

rc[number] = name

return rc

6

6. (10 points) Show the output of the following code:

places = { 'OR':{'Portland' : set(['Pearl District', 'Alameda']), 'Eugene' : set()},

'NY':{'Albany' : set(), 'NY' : set(['Chelsea', 'Harlem'])} }

print places['OR']['Eugene'] # <---

a = []

for place in places:

a += places[place].keys()

print a # <---

for x in a:

if len(x) < 7:

print x

for place in places:

if x in places[place]:

print places[place][x] # <---

Solution:

set([])

['Albany', 'NY', 'Portland', 'Eugene']

Albany

set([])

NY

set(['Harlem', 'Chelsea'])

Eugene

set([])

7. (12 points) Write a function called smallest_in_common that takes two dierent lists, both in in-

creasing order, and returns the smallest value that appears in both lists. Importantly, you may not

use a set, and you may not use a dictionary (these lead to simple code, but does more work than

necessary). The most credit will be given for solutions that scan through each list no more than once.

For example, if

l1 = [ 1, 3, 8, 12, 12, 15, 20 ]

l2 = [ 7, 9, 10, 11, 15, 30, 35 ]

l3 = [ 2, 4, 5, 13, 16, 17, 23, 25 ]

then

print smallest_in_common(l1,l2) # should output 15

print smallest_in_common(l1,l3) # should output None

Solution:

def smallest_in_common(l1, l2):

i = 0

j = 0

while i < len(l1) and j < len(l2):

if l1[i] < l2[j]:

i += 1

elif l1[i] > l2[j]:

j += 1

else:

return l1[i]

return None

7

8. (10 points) In order to sort a list of 2d point coordinates, [x,y], you need to write a function, which

we will call compare_points, that will be passed to the list sort function. compare_points should

take two points (lists of two values) p and q as arguments, and it should return -1 if p should be before

q, 1 if p should be after q, and 0 if p and q are equal. Write compare_points so that the ordering is

based on the rst value unless these values are the same. As examples,

print compare_points( [1,3], [5,6] ) # outputs -1

print compare_points( [1,3], [1,6] ) # outputs -1

print compare_points( [1,3], [1,3] ) # outputs 0

print compare_points( [1,3], [0,3] ) # outputs 1

Using this, the code

L = [ [5,8], [5,2], [12,3], [1,3], [10,2], [12,1], [12,3] ]

L.sort( cmp=compare_points )

print L

outputs

[[1, 3], [5, 2], [5, 8], [10, 2], [12, 1], [12, 3], [12, 3]]

Solution:

def compare_points( p, q ):

if p[0] < q[0]:

return -1

elif p[0] > q[0]:

return 1

elif p[1] < q[1]:

return -1

elif p[1] > q[1]:

return 1

else:

return 0

or

def compare_points( p, q ):

if p[0] < q[0] or (p[0] == q[0] and p[1] < q[1]):

return -1

elif p[0] > q[0] or (p[0] == q[0] and p[1] > q[1]):

return 1

else:

return 0

or

def compare_points( p, q ):

if p[0] < q[0] or (p[0] == q[0] and p[1] < q[1]):

return -1

elif p[0] == q[0] and p[1] == q[1]:

return 0

else:

return 1

8

## Much more than documents.

Discover everything Scribd has to offer, including books and audiobooks from major publishers.

Cancel anytime.