# Midterm Review

## Midterm Particulars

When and where
Thursday, October 28, 7:30 - 10:00 PM in MBH 216 (although the exam is intended to take less than 2 hours)
What can I bring?
• The cheat sheet handout on the course web page (I will bring copies of the cheat sheet to the exam so you don’t have to)
• One piece of letter paper with notes on both sides
What can’t I bring?
Anything else, e.g., book, computer, other notes, etc.
I have a scheduling conflict, can I take the midterm at an alternate time?
Yes. Hopefully you already responded to the Google form, to let me know. You can pick up the exam from me in my office on Thursday.

## What will the exam cover?

• Evaluating expressions (order of evaluation in parentheses, method chaining, etc.)
• Statements
• Function definitions (def …)
• for loops using collections, e.g. string, list, and ranges
• while loops (and the conversion between for loops and while loops)
• conditional statements (if, elif, else)
• return (and print vs. return)
• Types
• int
• float
• bool
• str
• list
• Strings and Lists
• Indexing and slicing
• Iterating
• Functions that take collection as arguments, e.g. len
• Methods
• Operators on type
• Operators
• +, -, *, /, //, %, **
• =, +=, -=, *=
• Boolean and relational operators
• and, or, not (and their precedence)
• <, <=, >, >=, ==, !=
• Using modules
• Different import approaches
• from <module> import <material>
• import <module> [as <prefix>]
• random module
• math module
• turtle module
• Input and output
• input function
• print function
• reading from files, including opening files via a with block
• Commenting (including block/inline comments and docstrings)
• Good coding style

The exam will NOT include material that was in the book(s) but that we did not discuss in class, or use in our labs, or practice in the problem sets. The exam will NOT include material in class 16+ (no sets, dictionaries, tuples or references).

## Types of questions

• Determine the output of code, e.g. value of variables, printing, turtle drawing
• Rewrite code with better style
• Identify bugs in code
• Write code to solve problem.

## How do you suggest I prepare?

• Practice, practice, practice! Complete the previous exams, (re)-solve the practice problems, the in-class PI problems, and the problems available on Coding Bat.
• Review the lecture notes. Treat the examples in the notes as practice problems.

## What do you suggest I put on my notes page?

Here are some (non-exhaustive) suggestions:

• Common code snippets, e.g., reading a file into a list, building up a string, determining even/odd, maintaining a count, determining min/max, etc.
• Common slicing patterns, e.g., every third value in a sequence, all but the first value in a sequence, etc.
• Common kinds of errors, e.g., mismatched type, off-by-one, missing colons, missing/invalid keywords, incorrect indent, etc.

## Review questions:

1. The following function is supposed to prompt the user for numbers until they enter a blank line, then it tells the user how many of the numbers were less than zero. Unfortunately, the function has a few problems and doesn’t work correctly. Identify and fix the problems. Show answer.

def neg_count():
answer = input("Enter a number: ")

below = 0

below += 1

print("Below: " + below)


Can be fixed as:

# Fixed neg_count
def neg_count():
answer = input("Enter a number: ")

below = 0

# Runtime error: Need to convert string to float
below += 1

# Logical error: Need to obtain subsequent inputs in each iteration of the loop

# Runtime error: Need to convert below to string before concatenation
print("Below: " + str(below))

2. Write a function called my_startswith that takes two strings as parameters and returns True if the first string starts with the second string. You may NOT use the built-in startswith method. You may assume that the second string is shorter than the first. Show answer.

def my_startswith(s1, s2):
n = len(s2)
return s1[:n] == s2


How would you modify the implementation if you could not assume s2 was shorter?

 def my_startswith(s1, s2):
n = len(s2)
return n <= len(s1) and s1[:n] == s2

3. Rewrite each of the boolean expressions below more compactly. For example, rather than writing x and x we could just write x.

# x contains some bool value
True and x


Can be rewritten as:

x

# x contains some bool value
False or x


Can be rewritten as:

x

y > 0 and y < 10


Can be rewritten as:

0 < y < 10

(y > 0 and z == 1) or (y > 0 and z == 2)


Can be rewritten as:

y > 0 and (z == 1 or z == 2)

(y > 0 and y < 10) and (y > 0 and y < 20)


Can be rewritten as:

y > 0 and y < 10


The expression y > 0 and y < 10 is a subset of y > 0 and y < 20 and so if that first expression is True, then the second expression must be True. Thus the overall expression will true if and only if the first expression is True.

(y > 0 and y < 10) and (y <= 0 or y >= 10)


Can be rewritten as:

False


The expression y > 0 and y < 10 is the same as not (y <= 0 or y >= 10) and such both operands can’t be True at the same time, thus the overall expression must be False.

4. Draw below what the following program would draw on the screen (Show answer):

from turtle import *

def draw_something(x, y, length):
pu()
goto(x, y)
pd()
goto(x + length, y)

for i in range(10):
draw_something(0, i*5, i*5)

done()


The above will draw horizontal lines of increasing length at increasing vertical coordinates.

5. For each of the statements below state whether an error would occur OR state what would be printed out. Make sure to make it clear whether you have printed an integer, a float or a string.

print(2 + 5.5)

>>> print(2 + 5.5)
7.5

print(15 / 2)

>>> print(15 / 2)
7.5

print(float(15 // 2))

>>> print(float(15 // 2))
7.0

print(2 + '3')

>>> print(2 + '3')
TypeError: unsupported operand type(s) for +: 'int' and 'str'

print(str(2) + '3')

>>> print(str(2) + '3')
"23"

6. Write a function called random_test that takes three integer parameters: max, threshold and num. The function should generate num random integers between 0 and max (inclusive) and return the number of these values that were less or equal to the threshold. Show answer.

from random import randint

def random_test(max, threshold, num):
count = 0
for i in range(num):
r = randint(0, max)
if r <= threshold:
count += 1
return count

7. If I have a file called “data.txt” that has the following data in it:

A 0
B 1
C 2
D 3
E 4


What would the following program print out? Show answer.

def process_file(filename):
a = []
b = []
with open(filename, "r") as file:
for line in file:
data = line.split()
a.append(data[0])
b.append(int(data[1]))

for i in range(len(a)):
print(a[i] * b[i])

process_file("data.txt")


The program would print the following. Note the initial blank line.


B
CC
DDD
EEEE

8. What would the following function return if we invoked it with 4 as the argument? Show answer.

def mystery(x):
count = 1
total = 0

while count <= x:
total += count * count



No return. count is never modified and so this is an infinite loop.

9. Imagine you are given a list of column positions in a building (in sorted ascending order). Write a function name span that takes the list as argument and returns the longest beam you will need to span between the columns, i.e., the maximum distance between any two adjacent columns. You can assume there are at least two columns. Show answer.

 def span(columns):
max_beam = 0 # Since columns are in sorted ascending order, the beam length must always be >= 0
for i in range(1, len(columns))
beam = columns[i] - columns[i-1]
if beam > max_beam:
max_beam = beam
return max_beam

10. What does the following expression evaluate to? Show answer.

len(("Mississippi" + "!").upper().replace("ss","a"))


12. The len argument evaluates as "Mississippi!".upper().replace("ss","a"). Since upper converts the string to MISSISSIPPI!, nothing is replaced. Thus we are evaluating len("MISSISSIPPI!"), which results in 12.

11. Write a function named intersection that has two lists as parameters and prints out every item in the first list that is present in the second list. It should only print each item once, even if it appears in the second list multiple times. Do not use a set. For example: Show answer.

 >>> intersection(["a", "b"], ["a", "a", "c"])
a


The simplest approach uses the in operator on lists.

 def intersection(list1, list2):
for item in list1:
if item in list2:
print(item)



If we do not use that operator, we can create the equivalent code with a nested for loop.

 def intersection(list1, list2):
for item in list1:
for match in list2:
if item == match:
print(item)
break


Here we use the break statement to terminate the inner loop once we have a match so that we don’t print item multiple times. We have previously used break with while loops, it can also be used with for loops. In the context of nested loops, break only terminates the current loop (not all loops). Alternately we can use a helper function to only match an item in list2 once. For example:

 def match_once(item, list2):
for match in list2:
if item == match:
return True
return False

def intersection(list1, list2):
for item in list1:
if match_once(item, list2):
print(item)


In match_once we return True immediately if there is a match (once we know the answer, no reason to continue the computation) and False only if there is no match (if we complete the loop there must not have been a match). Thus we will only print matching items once.