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?

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

How do you suggest I prepare?

What do you suggest I put on my notes page?

Here are some (non-exhaustive) suggestions:

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
       
        while answer != "":
            if answer < 0:
                below += 1
       
        print("Below: " + below)
    

    Can be fixed as:

    # Fixed neg_count
    def neg_count():
        answer = input("Enter a number: ")
       
        below = 0
       
        while answer != "":
            # Runtime error: Need to convert string to float
            if float(answer) < 0:
                below += 1
    
            # Logical error: Need to obtain subsequent inputs in each iteration of the loop
            answer = input("Enter a number:")
       
        # 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.

    1. Rewrite (Show answer):
      # x contains some bool value
      True and x
      

      Can be rewritten as:

      x
      
    2. Rewrite (Show answer):
      # x contains some bool value
      False or x
      

      Can be rewritten as:

      x
      
    3. Rewrite (Show answer):
      y > 0 and y < 10
      

      Can be rewritten as:

      0 < y < 10
      
    4. Rewrite (Show answer):
      (y > 0 and z == 1) or (y > 0 and z == 2)
      

      Can be rewritten as:

      y > 0 and (z == 1 or z == 2)
      
    5. Rewrite (Show answer):
      (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.

    6. Rewrite (Show answer):
      (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.

    1. Evaluate (Show answer):
      print(2 + 5.5)
      
      >>> print(2 + 5.5)
      7.5
      
    2. Evaluate (Show answer):
      print(15 / 2)
      
      >>> print(15 / 2)
      7.5
      
    3. Evaluate (Show answer):
      print(float(15 // 2))
      
      >>> print(float(15 // 2))
      7.0
      
    4. Evaluate (Show answer):
      print(2 + '3')
      
      >>> print(2 + '3')
      TypeError: unsupported operand type(s) for +: 'int' and 'str'
      
    5. Evaluate (Show answer):
      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
       
        return total
    

    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.