ELEX 4653 Exam 3 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.

Question 1

Write a function named bigvals(d,n) that takes a dict argument d and an integer argument n. d has integer keys and string values. Your function should return a list of all the values in d whose key is equal to or larger than n (in any order). For example, if d={97: 'a', 67: 'b', 92: 'c', 68: 'd'} and n=70 then bigvals(d,n) should return ['a', 'c'] (or ['c', 'a']).

In [1]:
def bigvals(d,n):
    return [v for k,v in d.items() if k >= n]

d={97: 'a', 67: 'b', 92: 'c', 68: 'd'}
n=70
bigvals(d,n)
Out[1]:
['a', 'c']

Question 2

Write a function named totalize(d) that takes one dict argument named d. Each element of d is a list of numbers. Your function should modify d by replacing each list with the sum of the values in that list. For example if d = {'a':[1], 'b':[1,2], 'c':[-1,0,1]} then after calling totalize(d) the value of d will be {'a': 1, 'b': 3, 'c': 0}.

In [2]:
def totalize(d):
    for k,v in d.items():
        d[k]=sum(v)

d =  {'a':[1], 'b':[1,2], 'c':[-1,0,1]}        
totalize(d)
d
Out[2]:
{'a': 1, 'b': 3, 'c': 0}

Question 3

Write a recursive function named listsquares(n,m) that takes two integer arguments , n and m and returns a list of the squares of the values between n and m inclusive. If n is greater than m an empty list should be returned. If n is equal to m a list containing only the single value n*n should be returned. For example listsquares(2,5) would return [4, 9, 16, 25].

In [3]:
def listsquares(n,m):
    if n > m:
        return []
    if n == m:
        return [n*n]
    else:
        return [n*n]+listsquares(n+1,m)  

listsquares(1,0),listsquares(10,10),listsquares(2,5)
Out[3]:
([], [100], [4, 9, 16, 25])

Question 4

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

  1. the sequence of letters PN: or Part=
  2. a number with 6 or 7 digits
  3. one of the letters X, Y or Z
  4. the optional letter X
  5. the string -ND
  6. the pattern is found at the end of the string

For example, re.search(pat,'PN:0123456XX-ND') would return a match object but re.search(pat,'PN:12345XX-ND') would not.

In [4]:
pat=r'(PN:|Part=)[0-9]{6,7}[XYZ]X?-ND$'

import re
re.search(pat,'PN:0123456XX-ND'),re.search(pat,'PN:12345XX-ND')
Out[4]:
(<re.Match object; span=(0, 15), match='PN:0123456XX-ND'>, None)

Marking Code

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 checkrecursive(f):
        s=f.__name__
        assert s in f.__code__.co_names, "{} is not recursive".format(s)
    
    def checkre(pat,ok,nok):
        for s in ok:
            assert re.search(pat,s), \
                f"pattern '{pat}'\n did not match string '{s}'"
        for s in nok:
            assert not re.search(pat,s), \
                f"pattern '{pat}'\n matched string '{s}'"

    def q1():
        k=list(set(choices(range(100),k=4)))
        v=randwords(len(k))
        n=randint(30,70)
        d=dict(zip(k,v))
        d0=copy.deepcopy(d)
        y=bigvals(d,n)
        z=list(map(lambda x:d0.__getitem__(x),filter(lambda x:x>=n,d0)))
        assert len(z) == len(y) and all([a==b for a,b in zip(y,z)]), \
            f'bigvals{d0,n} returns {y}'

    def q2():
        n=randint(2,3)
        d={k:choices(range(-1,9),k=randint(2,4)) for k in randwords(n)}
        d0=copy.deepcopy(d)
        totalize(d)
        import functools, operator
        assert not any(list({k:functools.reduce(operator.add,l)-d[k]
                             for k,l in d0.items()}.values())), \
            f'totalize(d)\n for d={d0}\n results in d={d}'

    def q3():
        import math
        checkrecursive(listsquares)
        l=listsquares(1,0)
        assert l == [], f'listsquares(1,0) returns {l}'
        l=listsquares(2,2)
        assert l == [4], f'listsquares(2,2) returns {l}'
        n=randint(0,3)
        m=n+randint(3,5)
        l=listsquares(n,m)
        assert [int(math.sqrt(i)) for i in l] == list(range(n,m+1)), \
            f'listsquares{n,m} returns {l}'
       
    def q4():
        import re
        ok  = [ 'PN:0123456XX-ND','Part=0123456XX-ND', 'PN:012345XX-ND',    
                'PN:0123456YX-ND','PN:0123456ZX-ND','PN:0123456X-ND',    
                'aaaPN:0123456XX-ND' ]
        nok = [ 'N:0123456XX-ND','Part:0123456XX-ND','PN:01234567XX-ND',
                'PN:01234XX-ND','PN:0123456AX-ND','PN:0123456XY-ND',
                'PN:0123456XX-N','PN:0123456XX-Naaa' ]
        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(f"Solution to question {i} may be correct.")
            except Exception as e:
                print(f"Failed check for question {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.