750 likes | 845 Views
EECS 110: Lec 17: Review for the Final Exam. Aleksandar Kuzmanovic Northwestern University. http://networks.cs.northwestern.edu/EECS110-s14 /. General Info. Wednesday, June 4, 9:30-11:30am, Kresge Centennial Hall 2415 To be done individually Closed book
E N D
EECS 110: Lec 17: Review for the Final Exam Aleksandar Kuzmanovic Northwestern University http://networks.cs.northwestern.edu/EECS110-s14/
General Info • Wednesday, June 4, 9:30-11:30am, Kresge Centennial Hall 2415 To be done individually Closed book One 8.5” by 11” sheet of paper permitted • Please do not discuss the exam with others until everyone has taken it. • There are six questions. Each question is worth 20 points. • Hence, you can acquire 120 points in total. • Those who get > 90 points will get an A. • Those who get >80 points and <90 points will get a B, etc.
Final Exam • 6 questions: • Misc • Loops and recursion • Mutation • 2D in Python • Dictionaries • Classes and Objects
Q2 (and Q1): Loops (while and for) and Recursion What does this code do? print('It keeps on') whileTrue: print('going and') print('Phew! I\'m done!’)
Extreme Looping Anatomy of a while loop: the loop keeps on running as long as this test is True print('It keeps on') whileTrue: print('going and') print('Phew! I\'m done!') “while” loop This won't print until the while loop finishes - in this case, never!
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) ??
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 ?? n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) 7
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 3 n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) 7
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 3 10 n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) 7
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 3 10 5 n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) 7
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 3 10 5 16 n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) 7
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 3 10 5 16 8 n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) 7
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 3 10 5 16 8 4 n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) 7
What do these two loops print? n = 3 while n > 1: print(n) if n%2 == 0: n = n/2 else: n = 3*n + 1 3 10 5 16 8 4 2 n = 0 for c in'forty-two': if c not in'aeiou': n += 1 print(n) 7
fore! x is assigned each value from this sequence 1 3 for x in range(8): print('x is', x) print('Phew!') LOOP back to step 1 for EACH value in the list the BODY or BLOCK of the for loop runs with that x 2 Code AFTER the loop will not run until the loop is finished. 4
Two kinds of for loops Element-based Loops Index-based Loops sum = 0 for x in L: sum += x sum = 0 for i inrange(len(L)): sum += L[i] i 1 2 0 L = [ 42, -10, 4 ] L = [ 42, -10, 4 ] x L[i]
Q2: Recursion vs. Loops • Solve a problem using: • (a) recursion • (b) loops
Example 1a: fac(N) with recursion Let recursion do the work for you. Exploit self-similarity Less work ! Produce short, elegant code deffac(N): if N <= 1: return 1 else: return N * fac(N-1) You handle the base case – the easiest possible case to think of! Recursion does almost all of the rest of the problem!
Example 1b: fac with for (v1) def fact( n ): answer = 1 for x in range(n): answer = answer * x return answer
Example 1b: fac with for (v2) def fact( n ): answer = 1 for x in range(1,n+1): answer = answer * x return answer
Example 2a: sum(L) with recursion defsum(L): """ input: a list of numbers, L output: L's sum """ if len(L) == 0: return 0.0 else: return L[0] + sum(L[1:]) Base Case This input to the recursive call must be "smaller" somehow… if the input has no elements, its sum is zero Recursive Case if L does have an element, add that element's value to the sum of the REST of the list…
Example 2b: sum(L) with for Finding the sum of a list: def sum( L ): """ returns the sum of L's elements """ sum = 0 for x in L: sum = sum + x return sum Accumulator!
Example 3: uniquify(L) Problem: Part A Use loops (no recursion!) to write a Python function uniquify(L), which takes in any list L and returns a list of the distinct elements in the list L. The order of the elements may be preserved, but they do not have to be. For example, >>> uniquify( [ 42, 'spam', 42, 5, 42, 5, 'spam', 42, 5, 5, 5 ] ) [ 'spam', 42, 5 ] >>> L = range(4) + range(3) >>> uniquify(L) [ 3, 0, 1, 2 ]
Example 3a: uniquify(L) def uniquify(L): s = [] for i in range(len(L)): n=0 for j in range(i+1,len(L)): if L[i] == L[j]: n=1 if n == 0: s=s+[L[i]] return s
Example 3: uniquify(L) Problem: Part B Use recursion (no loops!) to write a Python function uniquify(L), which takes in any list L and returns a list of the distinct elements in the list L. The order of the elements may be preserved, but they do not have to be. For example, >>> uniquify( [ 42, 'spam', 42, 5, 42, 5, 'spam', 42, 5, 5, 5 ] ) [ 'spam', 42, 5 ]
Example 3b: uniquify(L) def uniquify(L): if len(L) == 0: return [] else: if L[0] in L[1:]: return uniquify(L[1:]) else: return L[0:1] + uniquify(L[1:])
Question 3: Mutation Mutable vs. Immutable data Changeable types: Unchangeable types: tuple dictionary float string list bool int
Functions and (immutable) Variables deffact(a): result = 1 while a > 0: result *= a a -= 1 return result >>> x = 5 >>> y = fact(x) >>> x ?? NO SIDE EFFECTS!
Functions and (immutable) Variables deffact(a): result = 1 while a > 0: result *= a a -= 1 return result >>> x = 5 >>> y = fact(x) >>> x 5 NO SIDE EFFECTS!
Functions and (immutable) Variables x defswap(a, b): temp = a a = b b = temp >>> x = 5 >>> y = 10 >>> swap(x, y) >>> print(x, y) ?? y a b temp
Functions and (immutable) Variables x defswap(a, b): temp = a a = b b = temp >>> x = 5 >>> y = 10 >>> swap(x, y) >>> print(x, y) 5, 10 y a b temp
Functions and Mutable Types MyL defswap(L, i1, i2): temp = L[i1] L[i1] = L[i2] L[i2] = temp >>> MyL = [2, 3, 4, 1] >>> swap(myL, 0, 3) >>> print(myL) ?? L i1 i2 RAM 42 43 44 45
Functions and Mutable Types MyL defswap(L, i1, i2): temp = L[i1] L[i1] = L[i2] L[i2] = temp >>> MyL = [2, 3, 4, 1] >>> swap(myL, 0, 3) >>> print(myL) [1,3,4,2] L i1 i2 RAM 42 43 44 45
The conclusion You can change the contents of lists in functions that take those lists as input. (actually, lists or any mutable objects) Those changes will be visible everywhere. (immutable objects are safe, however)
Example 1 defzeroOdd1( L ): for i inrange(len(L)): if L[i] % 2 == 1: L[i] = 0 defzeroOdd2( L ): for i in L: if i % 2 == 1: i = 0 >>> L = [1, 2, 3, 4, 5] >>> zeroOdd1(L) >>> L ?? >>> L = [1, 2, 3, 4, 5] >>> zeroOdd2(L) >>> L
Example 1 defzeroOdd1( L ): for i inrange(len(L)): if L[i] % 2 == 1: L[i] = 0 defzeroOdd2( L ): for i in L: if i % 2 == 1: i = 0 >>> L = [1, 2, 3, 4, 5] >>> zeroOdd1(L) >>> L [0,2,0,4,0] >>> L = [1, 2, 3, 4, 5] >>> zeroOdd2(L) >>> L ??
Example 1 defzeroOdd1( L ): for i inrange(len(L)): if L[i] % 2 == 1: L[i] = 0 defzeroOdd2( L ): for i in L: if i % 2 == 1: i = 0 >>> L = [1, 2, 3, 4, 5] >>> zeroOdd1(L) >>> L [0,2,0,4,0] >>> L = [1, 2, 3, 4, 5] >>> zeroOdd2(L) >>> L [1,2,3,4,5]
Example 2 What are the values of A, B, C and D at the indicated points? def mystery1(L1, N, C): for i in L1: if i == N: C += 1 return C def mystery2(C): for i in range(len(C)): C[i] *= 2 >>> A = [22, 10, 30] >>> B = 22 >>> C = 0 >>> D = mystery1(A, B, C) >>> mystery2(A) 1) 2) 1 2
Example 2 What are the values of A, B, C and D at the indicated points? def mystery1(L1, N, C): for i in L1: if i == N: C += 1 return C def mystery2(C): for i in range(len(C)): C[i] *= 2 >>> A = [22, 10, 30] >>> B = 22 >>> C = 0 >>> D = mystery1(A, B, C) >>> mystery2(A) >>> A 1) 2) A = [22, 10, 30] B = 22 C = 0 D = 1 1 2
Example 2 What are the values of A, B, C and D at the indicated points? def mystery1(L1, N, C): for i in L1: if i == N: C += 1 return C def mystery2(C): for i in range(len(C)): C[i] *= 2 >>> A = [22, 10, 30] >>> B = 22 >>> C = 0 >>> D = mystery1(A, B, C) >>> mystery2(A) >>> A 1) 2) A = [22, 10, 30] B = 22 C = 0 D = 1 A = [44, 20, 60] 1 2
Example 3: avoiding mutation Problem: Write function x(L), …., The list L should NOT mutate, i.e., it should stay the same.
Example 3: avoiding mutation def x(L): # some function … L2=copyList(L) … # manipulate L2, not L def copyList(L): L2 = [] for x in L: L2 += [x] return L2
Question 4: 2D in Python Handling rectangular arrays … list list A[0] A A[0][0] list A[1] list A[2] A[2][3] How many rows does A have, in general ? How many columns does A have, in general ?
Rectangular arrays Handling rectangular arrays … list list A[0] A A[0][0] list A[1] list A[2] A[2][3] len(A) How many rows does A have, in general ? How many columns does A have, in general ?
Rectangular arrays Handling rectangular arrays … list list A[0] A A[0][0] list A[1] list A[2] A[2][3] len(A) How many rows does A have, in general ? len(A[0]) How many columns does A have, in general ?
Which one works? How could we create a rectangular array (of default data, 0), given its height and width ? A = [ [0]*width ]*height or A = [ [0]*height ]*width
Which one works? How could we create a rectangular array (of default data, 0), given its height and width ? A = [ [0]*width ]*height A = [ [0]*height ]*width
What's really going on? A = [ [0]*width ]*height inner = [0]*width A = [inner]*height
Creating a 2d array def create2dArray( width, height ): """ does just that """ A = [] # start with nothing for row in range( height ): for col in range( width ):
Creating a 2d array def create2dArray( width, height ): """ does just that """ A = [] # start with nothing for row in range( height ): A = A + [[]] for col in range( width ): A[row] = A[row] + [0] return A