# pre2revsol.py # CS 1110 Profs # April 2016 """Code corresponding to solutions for prelim 2 review questions. Uncomment problem-specific tests in the Application Script as you see fit.""" ########## Q1 (a) ########### def EvenOddSort(x): """ Performs an even-odd sort of x Precondition: x is a list with even length.""" evens = []; odds = [] for i in range(len(x)/2): # 'a', ...'h': range(4) == [0,1,2,3] ind = i*2 evens.append(x[ind]) odds.append(x[ind+1]) ## In order for the changes to ``last'' outside this function, # we need to change each entry of x. for ind in range(len(evens)): x[ind] = evens[ind] x[ind + len(evens)] = odds[ind] # Alternate way to perform the "copy entries in x" # Technically, one might argue that this solution violates the spirit of # the problem due to the "sorta kinda a slice" in the range function of the # first loop. def EvenOddSort_range_slicing(x): """ Performs an even-odd sort of x Precondition: x is a list with even length.""" evens= []; odds = [] for ind in range(0,len(x),2): # Ask yourself: why don't we do for ... in x? evens.append(x[ind]) odds.append(x[ind+1]) ### The rest of this is the same as in EvenOddSort. ## In order for the changes to ``last'' outside this function, # we need to change each entry of x. for ind in range(len(evens)): x[ind] = evens[ind] x[ind + len(evens)] = odds[ind] # Demonstrates what does wrong when you try to directly alter x --- # (You were warned ...) def EvenOddSort_wrong_because_direct(x): """ Performs an even-odd sort of x Precondition: x is a list with even length.""" # let's cheat to get right answer to make the paramter issue clearer cheat_result= x[0:len(x):2] + x[1:len(x):2] x = cheat_result # this changes what the param points to, # NOT what the caller's input was! def testq1a(): print 'testing Q1(a)' givenlist= ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] for fn in [ EvenOddSort, EvenOddSort_range_slicing, EvenOddSort_wrong_because_direct]: for startlist in [givenlist, [], ['a', 'b'], [0,1,2,3,4,5]]: x = list(startlist) # want to keep an unsorted copy! n = len(x) soln = x[0:n:2] + x[1:n:2] fn(x) if x != soln: print '\t' + str(fn)+': problem with', str(startlist)+': became', x print "finished running tests for Q1(a)" ########## Q1 (b) ########### def MultipleSort(x,N): """ Returns a list obtained by performing N even-odd sorts of the list x. The list x is not altered. Precondition: x is a list with even length and N is a positive int. """ copy = list(x) # Ask yourself: why make a copy? for i in range(N): EvenOddSort(copy) return copy ### Alternate implementation: explicit loop to make copy def MultipleSort2(x,N): """ Returns a list obtained by performing N even-odd sorts of the list x. The list x is not altered. Precondition: x is a list with even length and N is a positive int. """ copy = [] for ind in range(len(x)): copy.append(x[ind]) for j in range(N): EvenOddSort(copy) return copy def testq1b(): print 'testing Q1(b)' baselist = ['a', 'b', 'c', 'd', 'e', 'f'] for fn in [MultipleSort, MultipleSort2]: for answer in [ [baselist, 1, ['a', 'c', 'e', 'b', 'd', 'f']], [baselist, 2, ['a', 'e', 'd', 'c', 'b', 'f']]]: startlist = answer[0]; n = answer[1]; right = answer[2] x = list(startlist) response = fn(x,n) if response != right or x != startlist: print '\tproblem with', str(startlist)+": returned", response, \ 'and what we started with is now', x print "finished running tests for Q1(b)" ########## Q2 ########### import math class Point(object): """ Attributes: x the x-coordinate [float] y the y-coordinate [float] """ def __init__(self,x,y): self.x = x self.y = y def Dist(self,other): """ Returns a float that is the distance from self to other. Precondition: other is a Point """ return math.sqrt((self.x-other.x)**2+(self.y-other.y)**2) # for debugging def __str__(self): """Print (x,y)""" return "("+str(self.x)+','+str(self.y)+')' def __repr__(self): return str(self) def FarthestPt(L,idx,P): """ Returns an integer j with the property that the distance from L[j] to P is maximum among all the ***unvisited*** points. If idx[i] = 1, then we say that L[i] has been visited. If idx[i] = 0, then we say that L[i] is unvisited. Preconditions: L is a list of references to Point objects, P is a reference to a point object, and idx is a list of ints that are either zero or 1. The lists idx and L have the same length and idx has at least one zero entry. """ ind = idx.index(0) # find index of first unvisited (guaranteed to exist) max_d = P.Dist(L[ind]) # initialize max found so far max_d_ind = ind for ind in range(max_d_ind+1, len(L)): if idx[ind] == 0: # unvisited, check if P.Dist(L[ind]) > max_d: max_d = P.Dist(L[ind]) max_d_ind = ind return max_d_ind def FarthestPt_while(L,idx,P): """ Returns an integer j with the property that the distance from L[j] to P is maximum among all the ***unvisited*** points. If idx[i] = 1, then we say that L[i] has been visited. If idx[i] = 0, then we say that L[i] is unvisited. Preconditions: L is a list of references to Point objects, P is a reference to a point object, and idx is a list of ints that are either zero or 1. The lists idx and L have the same length and idx has at least one zero entry. """ ind = idx.index(0) # find index of first unvisited (guaranteed to exist) max_d = P.Dist(L[ind]) # initialize max found so far max_d_ind = ind # now ind is index of last checked unvisited while 0 in idx[ind+1:]: # still another unvisited one ind = idx.index(0, ind + 1) if P.Dist(L[ind]) > max_d: max_d = P.Dist(L[ind]) max_d_ind = ind return max_d_ind # Alternate implementation: doesn't do anything fancy with initialization def FarthestPt2(L,idx,P): """ Returns an integer j with the property that the distance from L[j] to P is maximum among all the ***unvisited*** points. If idx[i] = 1, then we say that L[i] has been visited. If idx[i] = 0, then we say that L[i] is unvisited. Preconditions: L is a list of references to Point objects, P is a reference to a point object, and idx is a list of ints that are either zero or 1. The lists idx and L have the same length and idx has at least one zero entry. """ d = 0 # max distance found so far for j in range(len(L)): dj = P.Dist(L[j]) if idx[j]==0 and dj>d: k = j # index of the farthest point found so far d = dj return k # will be defined because PreC guarantees an unvisited node def testq2(): print 'testing Q2' for fn in [FarthestPt,FarthestPt_while,FarthestPt2]: ptlist = [Point(0,1), Point(17,20), Point(-17, -20)] target = Point(0,2) for answer in [ [ptlist, [0, 1, 1], target, 0], [ptlist, [0, 0, 1], target, 1], [ptlist, [1, 0, 0], target, 2], [ptlist, [1, 1, 0], target, 2], [ptlist, [0, 0, 0], target, 2]]: input_list = answer[0] visited = answer[1] p = answer[2] right = answer[3] response = fn(input_list, visited, p) if response != right: print '\t'+str(fn)+': wrong because answer on\n\t\t' + str(input_list) \ + '\n\t\t' + str(visited) + '\n\t\t' + str(p), "\n\twas", response # (str(fn)+": wrong because answer on\n\t", input_list, visited, p, # 'was', response) print 'Finished testing Q2' ########## Q3 ########### def q31(): s = "abcd" for i in range(4): for j in range(i+1,4): print i, j, s[i]+s[j] def q32(): D1 = {'a':'one', 'b':'two', 'c': 'three', 'd':'four'} D2 = {'c':'five', 'd':'six', 'e':'seven','f':'eight'} D = {} for d in D1: D[d] = D1[d] for d in D2: D[d] = D2[d] for key in D: print key, D[key] ########## Q4 ########### def q4a(): x = [10,20,30] #for k in range(1000): for k in range(5): # let's just print the first 5 lines. print "k:", k, "x in the loop", x x.append(x[0]) x = x[1:4] def q4b(): P = Point(3,4) Q=P Q.x = 0 print Q.x, Q.y, P.x, P.y P = Point(7,8) print Q.x, Q.y, P.x, P.y def q4c(): x = [10,20,30,40] y=x for k in range(4): print "x is", x print "y is", y print "...." x[k] = y[3-k] print x ########## Q5 ########### def F(s,D): """ Returns True if s is a key for D and every element in D[s] is also a key in D. Otherwise returns False. Precondition: s is a nonempty string and D is a dictionary whose keys are strings and whose values are lists of strings. """ if s not in D: return False for item in D[s]: if item not in D: return False return True # Alternate, one-line implementation, using some python stuff def F2(s,D): """ Returns True if s is a key for D and every element in D[s] is also a key in D. Otherwise returns False. Precondition: s is a nonempty string and D is a dictionary whose keys are strings and whose values are lists of strings. """ return (s in D) and (all(item in D for item in D[s])) def testq5(): print "testing Q5" for fn in [F,F2]: # 'Eliza' is not a key D = {'males': ['John', 'Bob'], 'females': ['Mary', "Eliza"], 'John': 21, 'Bob': 22, 'Mary': 23} if not fn('males', D) or fn('females', D): print '\tsomething wrong with handling initial D', D # Now 'Eliza' is a key D['Eliza'] = 24 if not fn('males', D) or not fn('females', D): print '\tsomething wrong with handling initial D', D print "finished testing Q5" ############# Q6 ############### class City(object): """ attributes: name the name of a city [str] high: the record high temeratures [length-12 list of int] low: the record low temperatures [length-12 list of int] """ def __init__(self,cityName,theHighs,theLows): """Returns a reference to a City object. PreC: cityName is a string that names a city. theHighs is a length 12 list of ints. theHighs[k] is the record high for month k (Jan is month 0) theLows is a length 12 list of ints. theLowss[k] is the record high for month k (Jan is month 0) """ self.name = cityName self.high = theHighs self.low = theLows def HotMonths(self): """ Returns the number of months where the record high is strictly greater than 80. """ T = self.high # T is the list of temperature highs n = 0 for t in T: if t>80: n+=1 return n def Hotter(self,other): """Returns True if the city encoded in self has strictly more hot months than the city encoded in other. A month is hot if the record high for that month is > 80 PreC: other is a city object """ # What if you didn't have the parentheses? return self.HotMonths() > other.HotMonths() def Variation(self): """ Returns a length 12 list of ints whose k-th entry is the record high for month k minus the record low for month k. """ d = [] for k in range(12): diff = self.high[k]-self.low[k] d.append(diff) return d def Exaggerate(self): """ Modifies self.high so that each entry is increased by 1 and modifies self.low so that each entry is decreased by 1 . """ for k in range(12): self.high[k] += 1 self.low[k] -= 1 def Hottest(C): """ Returns an item from C that represents the city that has the most hot months. PreC: C is a list of references to City objects """ cMax = C[0] # Note: don't need to explicit keep the max-temp-so-far around, because # that value can be found in the object cMax for c in C: if c.Hotter(cMax): cMax = c return cMax def testq6(): print 'testing Q6' C1 = City('A',[50,60,70,80,85,90,95,90,85,70,60,45], [14,16,19,22,33,36,32,22,18,32,16,28]) C2 = City('B',[50,60,81,83,85,90,95,90,85,73,69,58], [12,26,15,26,33,38,52,42,11,19,23,38]) C3 = City('C',[50,60,70,71,75,80,77,63,74,99,76,52], [14,16,19,22,33,36,32,22,18,32,16,28]) LofC = [C1,C2,C3] for answer in [ [C1,5], [C2,7], [C3,1]]: city = answer[0] for method in [city.HotMonths]: response = method() right = answer[1] if response != right: print '\tHotMonths: problem with', city.name+': output was', response for answer in [[C1, C2, False], [C2, C1, True]]: first = answer[0]; second = answer[1] response = first.Hotter(second) right = answer[2] if response != right: print '\tHotter: problem with cities', first.name, 'and', second.name for answer in [[C1, [hi - li for hi, li in zip(C1.high, C1.low)]]]: city = answer[0] for method in [city.Variation]: response = method() right = answer[1] if response != right: print 'Variation: problem with', city.name+': output was', response C1 = City('A',[50,60,70,80,85,90,95,90,85,70,60,45], [14,16,19,22,33,36,32,22,18,32,16,28]) twin_city = City('twin of A',[50,60,70,80,85,90,95,90,85,70,60,45], [14,16,19,22,33,36,32,22,18,32,16,28]) twin_city.Exaggerate() right_highs = [t+1 for t in C1.high] right_lows = [t-1 for t in C1.low] if twin_city.high != right_highs: print '\tExaggerate: something wrong with high', twin_city.high if twin_city.low != right_lows: print '\tExaggerate: something wrong with low', twin_city.low hottest_city = Hottest(LofC) if (hottest_city is not C2): print '\tHottest: something wrong, thought the hottest was', hottest_city.name print "finished testing Q6" if __name__ == '__main__': # testq1a() # testq1b() testq2() # q31() # q32() # q4a() # q4b() # q4c() # testq5() # testq6()