ELEX 4653 Exam 1 Solutions

Instructions:

  • Answer all four (4) questions.

  • You have 110 minutes to complete the exam.

  • This is an open-book exam. All written material is allowed.

  • No electronic devices other than a flash drive and the lab PC may be used during the exam.

  • No communication with others (electronic, verbal, written or otherwise) is allowed during the exam. Violations will result in a mark of zero and disciplinary action.

  • Add the Python code described below in the cells provided.

  • Test your code using the menu item Cell ► Run All

  • The message Solution to question N may be correct. at the bottom of the notebook means that no errors were found in your answer to question N.

  • When the exam time is over, save the notebook (the .ipynb file) and upload it to the appropriate dropbox on the course web site.

Version 2 - corrected multiple errors in Question 3 and its marking code. (this question was not marked).

Question 1

Write a function named divisibleby(x,n) that takes a list argument named x and an integer argument n. Your function should return a (new) list consisting of all the values of x which are divisible by n. For example, if x=[0, 3, 4, 9] then divisibleby(x,3) should return [0, 3, 9].

In [1]:
def divisibleby(x,n):
    return [i for i in x if i%n == 0]

x=[0, 3, 4, 9]
divisibleby(x,3)
Out[1]:
[0, 3, 9]

Question 2

Write a function named mergedicts that takes one list argument named l. The list l contains dictionaries. Your function should return one list containing all key:value pairs in all dictionaries in l. For example if l = [{ 'a': 3, 'b': 9}, {1:2, "x":'y'}, {'sum':32}] then mergedicts(l) should return { 'a': 3, 'b': 9, 1:2, "x":'y', 'sum':32}. You may assume there are no duplicate keys.

In [2]:
def mergedicts(l):
    return {k:d[k] for d in l for k in d}

l = [{ 'a': 3, 'b': 9}, {1:2, "x":'y'}, {'sum':32}]
mergedicts(l)
Out[2]:
{'a': 3, 'b': 9, 1: 2, 'x': 'y', 'sum': 32}

Question 3

Write a recursive function named rtest that takes a string argument named s and function argument f. Your function should call f with successive characters of s until the return value is zero or all values of s have been tested. Your function does not return a value. For example if x='abc' and f('b') returns 0 then rtest would call f('a') and f('b') and then return. It would not call f('c').

In [3]:
def rtest(s,f):
    if not s or f(s[0]) == 0:
        return
    else:
        rtest(s[1:],f)
      
    
def f(c):
    print(c)
    return 0 if c == 'b' else 1
    
rtest("abc",f)
a
b

Question 4

Set the variable pat to a regular expression that matches a part number string created according to the following sequence:

  1. the letters XT
  2. one or two zeros (0 or 00)
  3. an optional letter M
  4. a 2- or 3-digit number
  5. the letter G or V
  6. the optional sequence -v2 at the end

For example, re.search(pat,'XT00M99V-v2') would return a match object but re.search(pat,'XT000M12G-v2') would not.

In [4]:
pat=r'^XT00?M?[0-9]{2,3}(G|V)(-v2)?$'

import re
re.search(pat,'XT00M99V-v2'),re.search(pat,'XT000M12G-v2')
Out[4]:
(<re.Match object; span=(0, 11), match='XT00M99V-v2'>, None)
In [5]:
# exam validation code; do not modify
def examcheck():
    import copy, hashlib, re
    from random import randint, choices, shuffle
    
    def randwords(n):
        l = set()
        while len(l)<n:
            l |= set((''.join([chr(randint(97,122)) for i in range(randint(2,5))]),))
        return list(l)
    
    def checksorted(l):
        assert all((l[i] <= l[i+1] for i in range(len(l)-1))), \
            "result is not sorted: {}".format(l)

    def checkfunctions(f,l):
        u=[s for s in f.__code__.co_names if s not in l]
        assert not u, "You used the function(s): {}".format(u)
        
    def checkrecursive(f):
        s=f.__name__
        assert s in f.__code__.co_names, "{} is not recursive".format(s)

    def checkhash(l,n):
        # print(hashlib.md5(''.join(l).encode('utf8')).hexdigest())
        assert hashlib.md5(''.join(l).encode('utf8')).hexdigest() == n, \
                'wrong values in list: {} ... {}'.format(l[0],l[-1])
    
    def checkre(pat,ok,nok):
        for s in ok:
            assert re.search(pat,s), \
                "pattern '{}' didn't match string '{}'".format(pat,s)
        for s in nok:
            assert not re.search(pat,s), \
                "pattern '{}' matched string '{}'".format(pat,s)

    def q1():
        import random
        n=random.randint(3,5)
        x1=random.sample(range(0,100,n),k=random.randint(2,4))
        x2=random.sample(range(0,100,n),k=random.randint(2,4))
        x2=[i+random.randint(1,n-1) for i in x2]
        x=x1+x2
        random.shuffle(x)
        x.sort()
        x1.sort()
        y=divisibleby(x,n)
        assert y == x1, f'divisible{x,n} returns {y} instead of {x1}'

    def q2():
        ll=[randint(2,4) for i in range(randint(2,4))]
        n=sum(ll)
        r=randwords(n)+list(range(n))
        shuffle(r)
        l=[{r.pop():r.pop() for i in range(n)} for n in ll]
        l0=copy.deepcopy(l)
        y=mergedicts(l)
        assert len(y) == n and all([k in y and y[k] == d[k] for d in l0 for k in d]), \
            "mergedicts({}) returns {}".format(l0,y) 

    def q3():
        import random
        checkrecursive(rtest)
        n=random.randint(3,5)
        s=''.join([chr(random.randint(ord('a'),ord('f'))) 
                   for i in range(random.randint(3,7))])
        sl=[]
        c=s[random.randint(0,len(s)-1)]
        def found(x):
            sl.append(x)
            return 0 if x == c else 1
        s0=copy.deepcopy(s)
        rtest(s,found)
        assert sl == list(s0[:s0.index(c)+1]), \
            f'rtest("{s}"",f) called f with {sl}'+ \
            f' when f("{c}") returns 0'
       
    def q4():
        ok=["XT00M123G-v2", "XT0M123G-v2", "XT00123G-v2", 
            "XT00M12G-v2", "XT00M123V-v2","XT00M123G"]
        nok=["X00M123G-v2", "XT000M123G-v2", "XT00m123G-v2", 
            "XT00M1234G-v2", "XT00M123X-v2", "XT00M123G0"]
        checkre(pat,ok,nok)  


    for i,s in ((i,'q%d'%i) for i in range(1,20)):
        if s in locals():
            try:
                locals()[s]()
                print("Solution to question {} may be correct.".format(i))
            except Exception as e:
                print("Failed check for question {}: {}".format(i,e))    

examcheck()
Solution to question 1 may be correct.
Solution to question 2 may be correct.
Solution to question 3 may be correct.
Solution to question 4 may be correct.