0% found this document useful (0 votes)
9 views12 pages

2023-Fall-Final 2

Uploaded by

vr2vfp9ry4
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views12 pages

2023-Fall-Final 2

Uploaded by

vr2vfp9ry4
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

Last Name: First: Netid:

CS 1110 Final, December 8th, 2023

This 150-minute exam has 8 questions worth a total of 100 points. Scan the whole test before
starting. Budget your time wisely. Use the back of the pages if you need more space. You may tear
the pages apart; we have a stapler at the front of the room.

It is a violation of the Academic Integrity Code to look at any exam other than your
own, look at any reference material, or otherwise give or receive unauthorized help.

You will be expected to write Python code on this exam. We recommend that you draw vertical
lines to make your indentation clear, as follows:

def foo():
if something:
do something
do more things
do something last

Unless you are explicitly directed otherwise, you may use anything you have learned in this course.
You may use the backside of each page for extra room for your answers. However, if you do this,
please indicate clearly on the page of the associated problem.

Question Points Score


1 2
2 9
3 18
4 16
5 14
6 12
7 14
8 15
Total: 100

The Important First Question:


1. [2 points] Write your last name, first name, and netid at the top of each page.
Last Name: First: Netid:

References
String Operations

Expression Description

len(s) Returns: Number of characters in s; it can be 0.


a in s Returns: True if the substring a is in s; False otherwise.
s.find(s1) Returns: Index of FIRST occurrence of s1 in s (-1 if s1 is not in s).
s.count(s1) Returns: Number of (non-overlapping) occurrences of s1 in s.
s.islower() Returns: True if s is has at least one letter and all letters are lower case;
it returns False otherwise (e.g. 'a123' is True but '123' is False).
s.isupper() Returns: True if s is has at least one letter and all letters are upper case;
it returns False otherwise (e.g. 'A123' is True but '123' is False).
s.lower() Returns: A copy of s but with all letters converted to lower case
(so 'A1b' becomes 'a1b').
s.upper() Returns: A copy of s but with all letters converted to upper case
(so 'A1b' becomes 'A1B').
s.isalpha() Returns: True if s is not empty and its elements are all letters; it returns
False otherwise.
s.isdigit() Returns: True if s is not empty and its elements are all numbers; it returns
False otherwise.
s.isalnum() Returns: True if s is not empty and its elements are all letters or numbers;
it returns False otherwise.

List Operations

Expression Description

len(x) Returns: Number of elements in list x; it can be 0.


y in x Returns: True if y is in list x; False otherwise.
x.index(y) Returns: Index of FIRST occurrence of y in x (error if y is not in x).
x.count(y) Returns: the number of times y appears in list x.
x.append(y) Adds y to the end of list x.
x.insert(i,y) Inserts y at position i in x. Elements after i are shifted to the right.
x.remove(y) Removes first item from the list equal to y. (error if y is not in x).

Dictionary Operations

Expression Description

len(d) Returns: number of keys in dictionary d; it can be 0.


y in d Returns: True if y is a key in dictionary d; False otherwise.
d[k] = v Assigns value v to the key k in dictionary d.
del d[k] Deletes the key k (and its value) from the dictionary d.
d.clear() Removes all keys (and values) from the dictionary d.

Page 2
Last Name: First: Netid:

2. [9 points total] Short Answer


(a) [3 points] What is a fruitful function? What is a procedure? Give an example of each.

(b) [3 points] Execute the four statements below. What is printed out? Explain your answer.
>>> a = [1,2]
>>> b = a[:]
>>> print (a == b)
>>> print (a is b)

(c) [3 points] What are the names of the two sorting algorithms that take n2 steps to complete?
What is the difference between them?

Page 3
Last Name: First: Netid:

3. [18 points total] Testing and Exceptions


(a) [10 points] Consider the following function specification.
def is_csv(value):
"""Returns True if value is a table of strings (CSV table); False otherwise.

A table is a 2d list containing non-empty lists of the same length. An


example of a CSV table would be [['a','b'],['c','d']]
Precond: value is a non-empty list (it can be any list)"""
Do not implement this function. Instead, provide a list of at least six test cases to test
this function. For each test case provide: (1) the function input, (2) the expected output,
and (3) an explanation of what makes this test significantly different. To be different, the
examples should prioritize the most important things checked by this function.

(b) [4 points] Given the function below, enforce its preconditions (but do not implement it)
according to the specification. You should not use assert statements. Instead, write
code that produces the errors specified. You may use the function above as a helper.
def flatten(value):
"""Returns a CSV table flattened into a list of strings.

Example: flatten([['a','b'],['c','d']]) returns ['ab','cd']


Precond: value is a valid CSV table. This function produces a TypeError if
it is not a list, and a ValueError if it is a list but not a CSV table."""

# Do NOT implement this function. Precondition only.

Page 4
Last Name: First: Netid:

(c) [4 points] Implement the function below. You may use any of the previous two function
as helpers. However, you may not use if-statements; you must use try-except.
def flatten_if_safe(value):
"""Returns the flattened list of value IF it is a CSV table.

If value is a list but not a CSV table, this function returns the empty
list. If it is not a list, this function returns None.
Precond: value can be ANYTHING"""

4. [16 points] Call Frames

Suppose we have a list a = [5,4], together with the recursive function reverse shown below.

1 def reverse(seq):

id1
2 """Returns the reverse of seq"""
3 right = seq[1:] a id1
4 if right == []: list
5 return seq
6 0 5
7 left = seq[:1] 1 4
8 return reverse(right)+left

On the next two pages, diagram the evolution of the function call

b = reverse(a)

Diagram the state of the entire call stack for the function reverse when it starts, for each line
executed, and when the frame is erased. If any other functions are called, you should do this
for them as well (at the appropriate time). This will require a total of ten diagrams.
You should draw also the state of global space and the heap at each step. You can ignore the
folders for the function definitions. Only draw folders for lists or objects. To help conserve
time, you are allowed (and encouraged) to write “unchanged” if no changes were made to
either a call frame, the global space, or the heap. In the case of the heap, you can point out
that individual folder ids are unchanged.

Page 5
Last Name: First: Netid:

Call Stack Global Space The Heap


1

id2

id2

Page 6
Last Name: First: Netid:

Call Stack Global Space The Heap


6

id2

id2

id2

10

Page 7
Last Name: First: Netid:

5. [14 points] Classes and Subclasses


For this question, you are going to use the classes of
Assignment 7 to make a GSlider. Shown to the right,
this is a GUI element that you used to change the colors (x1,y1)
in Assignment 3. A slider is built up of two graphical (x0,y0)
objects, a GPath and a GEllipse. The former is the
line that displays the path of the slider. The latter is
the knob that the user drags to control the slider.
One easy way to make a GUI element composed of two different objects is to make the class
a subclass on one and have the other as an attribute. That is what we have done on the next
page. GSlider is a subclass of GPath but it has a _knob attribute for the GEllipse.
For this question, you only need to pay attention to the points attribute of GPath; all other
attributes can be left to their default values (e.g. the line color can be left as the default
'black'). The points attribute is an even-length list of numbers (ints or floats) expressing
the points the path goes through. For example, a line segment from (0,1) to (5,-3) would have
points attribute [0,1,5,-3].
For the class GEllipse you only need to know the following attributes.

Attribute Invariant Description


x float or int x-coordinate of the ellipse center.
y float or int y-coordinate of the ellipse center.
width float > 0 or int > 0 The width along the central horizontal axis.
height float > 0 or int > 0 The height along the central vertical axis.
fillcolor str The interior color (given as the name, e.g. 'blue').
In addition, remember that both GPath and GEllipse use keyword arguments in their construc-
tors. So to create a red ellipse of radius 10 at the origin, you would specify

ellipse = GEllipse(x=0,y=0,width=20,height=20,fillcolor='red')

Implementing mouse control is too messy for an exam, so we control the slider with an additional
attribute called _value. This attribute must be in sync with the knob. When it changes, the
knob moves (we will not worry about what to do when the knob moves first). This is expressed
by the specification on the next page.
With this in mind, implement this class on the next page. We have provided the specifications
for the methods __init__ and draw. You should fill in the missing details to meet these
specifications. In addition, you must add the getters and setters (where appropriate) for the new
attributes. Remember that setters must have preconditions to enforce the attribute invariants.
All type-based preconditions should be enforced by isinstance.
Hint: The attributes in GPath and GEllipse work like they do in Assignment 7, and have
invisible setters and getters. Therefore, you never have to enforce the invariants for these
attributes. You only need to worry about your new attributes: _knob and _value.

Page 8
Last Name: First: Netid:

class GSlider(GPath):
"""A class representing a graphical slider."""
# MUTABLE ATTRIBUTES:
# Invariant: _value is a float in 0 to 1, inclusive
# IMMUTABLE ATTRIBUTES:
# Invariant: _knob is a GEllipse
# ADDITIONAL INVARIANT
# If the slider path is from (x0,y0) to (x1,y1), the _knob is located at
# x = (x1-x0)*_value+x0, y =(y1-y0)*_value+y0
# DEFINE GETTERS/SETTERS AS APPROPRIATE. SPECIFICATIONS NOT NEEDED.

def __init__( ): # Fill in parameters


"""Initializes a slider whose path is from (x0,y0) to (x1,y1)

The initial value is 0. The slider line is black, which is the default color
(no need to set it). The knob has the given radius and a fillcolor of 'blue'.
Precond: x0, y0, x1, and y1 (in that order) are all ints
Precond: radius is an int >= 1 (OPTIONAL; default 10)"""

def draw( ): # Fill in parameters


"""Draws the knob ON TOP of the slider path.

Precond: view is a GView object"""

Page 9
Last Name: First: Netid:

6. [12 points] Nested Lists


A triangular list is a ragged list whose rows start (end) at size one and increase (decrease) by
one each row. Unlike a table, not all rows have the same number of columns. But the length of
the largest column is equal to the number of rows.
Triangular lists come in two forms. In an upper triangular list, the largest row is the first one.
In a lower triangular list, the largest row is the last one. Examples of these are shown below.

[ [1, 2, 4, 5], [ [5],


[0, 6, −2], [4, −2],
[3, −1], [2, 6, −1],
[8] ] [1, 0, 3, 8] ]
Upper Triangular List Lower Triangular List

The function rot_ccw below takes an upper triangular list and rotates it counter-clockwise.
This is similar to transpose (shown in class) where rows are swapped with columns. But the
rows in the rotated copy are arranged in reverse order from the columns in the original.
For example, rot_ccw takes the upper triangular matrix above on the left and returns the lower
triangular matrix on the right. With this explanation, implement the function below.
Hint: Do not think about looping over the original triangular list. That will confuse you.
Think about looping over the list you are returning (the one you are building), and then figure
out how to get the elements you want from the original list.
def rot_ccw(tri):
"""Returns a new lower triangular list from rotating tri counter-clockwise

Precondition: tri is an upper triangular list"""

Page 10
Last Name: First: Netid:

7. [14 points] Recursion and Iteration


Some of you may remember Pascal’s Triangle from your algebra class.
This triangle gives you the coefficients when you raise the polynomial 1
(x + 1) to a power. This triangle is shown to the right. We refer to 1 1
each row of the triangle as a level, and a level can be represented as a 1 2 1
list of ints. The row [1] is the 0th level, row [1, 1] is the 1st level, 1 3 3 1
row [1, 2, 1] is the 2nd level and so on. 1 4 6 4 1
As shown on the right, we compute each level from the previous one.
We put new 1s at the start and end of the level. For the values in- Rule:
between, we add two adjacent elements from the previous level. As 1 1
a result, each level has exactly one more element than the previous
level.
1 2 1
Implement the function below which computes the specified level of 1 3 3 1
the Pascal triangle. You do not need to enforce the precondition.
Important: Your solution must use recursion, but you are also allowed to use a loop as well.
Note that this question is not a divide-and-conquer problem. Read the paragraph above to see
the recursive definition.

def pascal_level(n):
"""Returns: the nth level of the pascal triangle

Precondition: n is an int >= 0."""

Page 11
Last Name: First: Netid:

8. [15 points total] Generators


Implement the generators below using anything learned in class. However, note the precondition
of bythrees. Iterables that are not lists or strings cannot be sliced and have no length.
(a) [6 points]
def bythrees(stream):
"""Generates every third element of the iterable stream

Ex: bythrees([1,5,7,0,2,4,3]) generates 1, 0, 3


Ex: bythrees([1]) generates 1
Precond: stream is iterable (can be used in a for-loop)"""
# HINT: Look at the precondition. stream is NOT a sequence

(b) [9 points]
def fibfrom(n):
"""Generates the Fibonnacci sequence, starting with the nth value.

The Fibonnaci sequence starts with 1 and 1, and adds the previous two values
to get the next value. This sequence is infinite, so the generator is too.
Ex: fibfrom(0) generates 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
Ex: fibfrom(4) generates 5, 8, 13, 21, 34, ...
Precond: n >= 0 is an int"""
# HINT: You do not need recursion for this. Do not use recursion.

Page 12

You might also like