The final exam will look like the midterm but longer - 2 hours with proportionately more questions. The time and location will be published on the course page. As with the midterm, we will not grade off for superficial syntax type errors. Also, exams are not generally graded on style or decomposition (those being more homework-project topics), so long as your solution gets the correct output.
The exam will cover all of the course material - midterm and post-midterm. This page does not repeat the midterm study material, so see the midterm-prep document and the midterm itself for those study questions.
Main coding topics since midterm:
1. Look at the first and last problems on this page - "Warmup" is a new problem format we'll use. And the last problem q10 prime_file() is a nice summary sort of problem - combining many CS106AP techniques in one problem.
2. Midterm - The midterm and practice-midterm make excellent practice problems. It does not matter that you have seen the solution at one time. Confront these problems with a blank piece of paper, and you will likely find that your Python brain cells are getting a little workout. A fraction of the final exam will be on midterm topics.
4. Published Final Exams - it's always nice to look at an actual published exam, even if the emphasis each quarter is a little different. See our course page.
5. Homeworks/Sections - Often a core function from a homework influences some exam problems. If there is a function that you found to be tricky on a homework, you should review your solution and understand how it works (e.g. add_name()). Often there is a section or lecture problem published with solution code that resembles the most difficult parts of each homework.
1. Select a problem (it's fine to do the same problem repeatedly until you have it cold)
2. Working from a blank piece of paper, try to solve it (make a drawing)
3. When done, compare your answer to the solution .. repeat
Just gazing at solution code doesn't count as practice for this sort of exam, tempting though it may be. Gazing at the solution is a trap!
The exam will include printed on it a few reminders of python functions we have used. The list is longer than on the midterm.
Of course the key is knowing how to call them. We will not generally grade off for syntax. The emphasis is on passing the right numbers to range() or in a slice, and example problems below all feature that sort of complexity. If a question needs a function from a module, such as random.randrange() or TK create_line(), the question text will include the documentation for that function.
# CS106AP Exam Reference Reminder
General functions:
len() int() str() range() list()
sorted() # key= and reverse= optional params
min() max() # key= optional param
String functions:
isalpha() isdigit() isspace() isalnum() find()
startswith() endswith()
isupper() islower() upper() lower()
replace() split() join() format() splitlines()
List functions:
append() extend() pop() map()
Dict functions:
keys() values() items()
File functions
with open(filename, 'r') as f: # with form
f = open(filename, 'r') # f = form
for line in f: # loop over lines
s = f.read() # read as one big string
lines = f.readlines() # read as list of strings
Lambda syntax:
lambda n: 2 * n
SimpleImage:
image = SimpleImage(filename)
image = SimpleImage.blank(width, height)
image has .width and .height int properties
for pixel in image: # loop pixel over whole image
pixel = image.get_pixel(x, y) # access pixel by x,y
pixel has .x .y .red .green .blue
pix = image.get_pix(x, y) # pix (r, g, b) tuple form
image.set_pix(x, y, pix)
# loop over all pixel x,y
for y in range(image.height):
for x in range(image.width):
pixel = image.get_pixel(x, y)
Warmup-1 - "warmup" question type, requires looking at code carefully instead of writing code.
For each expression, write exactly what Python will print. These expressions each yield a non-erroneous result.
>>> # a
>>> 1 + 2 * 4
>>> # b
>>> 1 + 2.0 + 3
>>> # c
>>> 5 / 2
>>> # d
>>> a = 1
>>> b = 50
>>> a > 10 or b < 100 # evaluates to True or False
>>> a > 10 and b < 100
>>> # e
>>> s = 'Spring'
>>> s[1:3]
>>> s[:3]
>>> s[3:]
>>>
>>> # f - dict + sort
>>> d = {'ca': 'california', 'ak': 'alaska', 'tx': 'texas'}
>>> sorted(d.keys())
>>> # g - comprehension - dense!
>>> [ s[1] for s in sorted(d.values()) ]
>>> # h - sort/lambda
>>> pairs = [(3, 1), (4, 5), (6, 3)]
>>> sorted(pairs, key= lambda pair: pair[1])
Warmup-2 - function call trace. What 3 numbers are printed by the run of caller() below?
def cat(x, y):
x = 0
return x + y
def caller():
x = 10
y = 20
z = cat(x, x + y)
# What 3 numbers does this print?
print(x, y, z)
q1. Given a dict 'mapping' which maps every key char like 'a' to its value char like 'z' and a string s. Return a new string where every char in s that is in mapping has been replaced by its mapped value. Treat upper/lower case as different. So for example the mapping {'a': 'z', 'b': 'x'} changes 'a' to 'z' and 'b' to 'x'.
def crypt(mapping, s):
# your code here
q2. Given a 'mapping' dict from the previous problem. Compute and return a reverse mapping, so if the original mapping maps 'a' to 'z', the reverse mapping maps 'z' to 'a'. Assume the values in the mapping dict are all unique. Suggestion: one approach is using the dict.items() function.
def reverse_crypt(mapping):
q3. Given 'reps' an even-length list of non-empty strings and a string s. For the strings at index 0, 2, 4, ... in the list, replace that substring in s with the one at index 1, 3, 5. So for example reps ['aa', 'bb', 'cc', 'dd'] means to replace all 'aa' substrings with 'bb' and then all 'cc' with 'dd'. Return a version of s with all these replacements done.
def replacing(reps, s):
q4. Given a 'pairs' list of strings where each string is of the form of a word-colon-number like this: ['apple:27', 'dog:2', 'donut:42', ...]. The word is non-empty and is made of chars that are not a colon.
Create and return a dict with a key for each word, and its value is the sum of all the numbers seen for that word. '''
def pairsum(pairs):
q5. Another question format: the spec is given within the """ ..."""", sometimes with Doctests shown too. You only need to write Doctests when the question specifically asks you to write them.
def evens(line):
"""
Given a line of text, return a string
made of its chars at index 0, 2, 4, ...
Except: do not include the last char in the line.
so the line 'abcdefg' yields 'ace',
"""
q6.
def evens_file(filename):
"""
Given a filename, read all the lines out of
it and print 'evens' versions of each line.
(Call the previous function)
"""
q7.
def all_words(filenames):
"""
Given a list of filenames of text files.
Read all the text out of each file, splitting into "words" by whitespace.
Add all these words into a big list (word duplication preserved).
Return this list sorted into increasing order.
"""
q8.
def make_county(words):
"""
Given a list of non-empty words, produce 'county' dict
where each first-char-of-word seen is a key, and its value
is a count dict of words starting with that char.
So ['aaa', 'abb', 'aaa'] yields {'a': {'aaa':2, 'abb':1}}
>>> make_county(['aaa', 'abb', 'aaa']) == {'a': {'aaa':2, 'abb':1}}
True
"""
q9. This problem originally involved creating SVG text graphics. This quarter we did TK drawing, so the problem has been translated to use create_line().
def draw_percents(canvas, percents):
"""
Given a width=500 height=500 canvas, and
a list of percent values, each in the range 0 .. 100 inclusive.
Draw a black vertical line for the first percent at x=0, the next at x=1,
and so on.
Each vertical line should be 1 pixel wide, start at the bottom of the canvas
and stretch up towards the top proportionate to the percentage.
TK create_line reminder, draw a black 1-pixel-wide line:
canvas.create_line(x1, y1, x2, y2)
"""
q10.
def prime_file(filename):
"""
The given file contains text data on each line as follows.
Each line is made of a mixture of non-empty alphabetic words
and non-negative ints, all separated by colons. The numbers can be distinguished
since their first char is a digit. Lines like this:
aaa:123:420:xyz:xxx:44:zz:a
The first element is the "prime" for that line, and is always alphabetic.
Read through all the lines and build a dictwith a key for each prime,
and its value is a list of all the int number values from all the lines
with that prime.
Add every number to the list, even if it is a duplicate.
When all the data is loaded, print the primes in alphabetical order
1 per line, each followed by its sorted list of numbers, like this
aaa [44, 123, 123, 125, 420, 693]
bbb [16, 23, 101, 101]
...
...
"""
primes = {}
## Warmup 1
>>> # a
>>> 1 + 2 * 4
9
>>> # b
>>> 1 + 2.0 + 3
6.0 # Note: float
>>> # c
>>> 5 / 2
2.5
>>> # d
>>> a = 1
>>> b = 50
>>> a > 10 or b < 100 # evaluates to True or False
True
>>> a > 10 and b < 100
False
>>> # e
>>> s = 'Spring'
>>> s[1:3]
'pr'
>>> s[:3]
'Spr'
>>> s[3:]
'ing'
>>>
>>> # f - dict + sort
>>> d = {'ca': 'california', 'ak': 'alaska', 'tx': 'texas'}
>>> sorted(d.keys())
['ak', 'ca', 'tx']
>>>
>>> # g - comprehension - dense!
>>> [ s[1] for s in sorted(d.values()) ]
['l', 'a', 'e']
>>>
>>> # h - sort/lambda
>>> pairs = [(3, 1), (4, 5), (6, 3)]
>>> sorted(pairs, key= lambda pair: pair[1])
[(3, 1), (6, 3), (4, 5)]
## Warmup 2
caller() prints: 10 20 30
## q1
def crypt(mapping, s):
result = ''
for ch in s:
if ch in mapping:
result += mapping[ch]
else:
result += ch
return result
## q2
def reverse_crypt(mapping):
pass
result = {}
for pair in mapping.items():
# pair is (key, value)
result[pair[1]] = pair[0]
return result
## q3
def replacing(reps, s):
for i in range(0, len(reps), 2):
s = s.replace(reps[i], reps[i+1])
return s
## q4
def pairsum(pairs):
counts = {}
for pair in pairs:
parts = pair.split(':') # or could use .find()
word = parts[0]
num = int(parts[1])
if not word in counts:
counts[word] = 0
counts[word] += num
return counts
## q5
def evens(line):
"""
Given a line of text, return a string
made of its chars at index 0, 2, 4, ...
Except: do not include the last char in the line.
so the line 'abcdefg' yields 'ace'.
"""
result = ''
for i in range(0, len(line)-1, 2): # -1 here is key
result += line[i]
return result
## q6
def evens_file(filename):
"""
Given a filename, read all the lines out of
it and print 'evens' versions of each line.
(Call the previous function)
"""
with open(filename, 'r') as f:
for line in f:
print(evens(line))
## q7
def all_words(filenames):
"""
Given a list of filenames of text files.
Read all the text out of each file, splitting into words by whitespace.
Add all these words into a big list (duplication allowed).
Return this list sorted into increasing order.
"""
all = []
for filename in filenames:
with open(filename, 'r') as f:
text = f.read()
words = text.split()
all.extend(words)
return sorted(all)
## q8
def make_county(words):
"""
Given a list of non-empty words, produce 'county' dict
where each first-char-of-word seen is a key, and its value
is a count dict of words starting with that char.
So ['aaa', 'abb', 'aaa'] yields {'a': {'aaa':2, 'abb':1}}
"""
county = {}
for word in words:
ch = word[0]
if ch not in county:
county[ch] = {}
inner = county[ch]
if not word in inner:
inner[word] = 0
inner[word] += 1
return county
## q9
def draw_percents(canvas, percents):
"""
Given a width=500 height=500 canvas, and
a list of percent values, each in the range 0 .. 100 inclusive.
Draw a black vertical line for the first percent at x=0, the next at x=1,
and so on.
Each vertical line should be 1 pixel wide, start at the bottom of the canvas
and stretch up towards the top proportionate to the percentage.
QT create_line reminder, draw a black 1-pixel-wide line:
canvas.create_line(x1, x2, y1, y2)
"""
for i in range(len(percents)):
height = (percents[i]/100) * 500 # height of this bar
# x is just i, y1 is 499, think hard about y2
canvas.create_line(i, 499, i, 500 - height)
## q10
def prime_file(filename):
"""
The given file contains text data on each line as follows.
Each line is made of a mixture of non-empty alphabetic words
and non-negative ints, all separated by colons. The numbers can be distinguished
since their first char is a digit. Lines like this:
aaa:123:420:xyz:xxx:44:zz:a
The first element is the "prime" for that line, and is always alphabetic.
Read through all the lines and build a dict with a key for each prime,
and its value is a list of all the int number values from all the lines
with that prime.
Add every number to the list, even if it is a duplicate.
When all the data is loaded, print the primes in alphabetical order
1 per line, each followed by its sorted list of numbers, like this
aaa [44, 123, 123, 125, 420, 693]
bbb [16, 23, 101, 101]
"""
primes = {}
with open(filename, 'r') as f:
for line in f:
parts = line.split(':')
prime = parts[0]
# pick out which parts are ints - comprehension is cute here
# or could do this as a regular old for-loop with an append
# inside is fine and full credit.
nums = [int(part) for part in parts if part[0].isdigit()]
if not prime in primes:
primes[prime] = []
primes[prime].extend(nums)
# now output
for prime in sorted(primes.keys()):
print(prime, sorted(primes[prime]))