ELEX 4653 Lab 2¶

This lab provides practice on expressions, lists, dictionaries, control flow statements and functions.

Instructions:

  • Modify this notebook by adding the Python code described below.

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

  • Save the notebook (the .ipynb file) and upload it to the appropriate Assignment folder on the course web site.

Question 1¶

Write a function, substrings(s) that returns a list containing all possible initial substrings from s in increasing length. For example if s is "abc123" then substrings(s)should return ['a', 'ab', 'abc', 'abc1', 'abc12', 'abc123'].

In [1]:
def substrings(s):
    return [s[:i] for i in range(1,len(s)+1)]

substrings("abc123")
Out[1]:
['a', 'ab', 'abc', 'abc1', 'abc12', 'abc123']

Question 2¶

Write a function, reverseif(l,p), where l is a list of strings and a p is a list of booleans. The function should return a list whose i'th element is:

  • l[i] if p[i] is False, or
  • l[i] with the order of the characters reversed if p[i] is True.

For example, reverseif(['abc', '123', 'xyzzy', 'zebra'], [True, False, False, True])should return ['cba', '123', 'xyzzy', 'arbez'].

In [2]:
def reverseif(l,p):
    return [s[::-1] if r else s for s,r in zip(l,p)]
    
reverseif(['abc', '123', 'xyzzy', 'zebra'], [True, False, False, True])
Out[2]:
['cba', '123', 'xyzzy', 'arbez']

Question 3¶

Write a function, removechars(s,x), that returns a set of the characters in the string s that are not in the string x.

For example, removechars('giraffe',"aeiou")should return {'g', 'r', 'f'} (with the items in any order).

In [3]:
def removechars(s,x):
    return set(s)-set(x)

Question 4¶

Write a function sumvalues(d) that returns a dictionary whose items have the keys in the dictionary d and whose values are the sums of the iterable values in d. For example, if d is {32:(1,2,3), 'xyz':{4,5,6}, (1,2):[5,9,10,11]} then sumvalues(d) should return {32:6, 'xyz':15, (1,2):35}.

In [4]:
def sumvalues(d):
    return {k:sum(v) for k,v in d.items()}

Question 5¶

Write a function toggletype(x) that toggles the type of x and each item in x. For this question toggle means to change the type of the object from list to tuple or vice-versa. For example, toggletype(([1,2,3],('ab','c'),("hello",))) would return [(1,2,3),['a','b'],["hello"]] and toggletype([(1,2,3),['ab','c'],["hello"]]) would return ([1, 2, 3], ('ab', 'c'), ('hello',)).

In [5]:
def toggletype(x):
    l=[]
    for i in x:
        if type(i) == list:
            l.append(tuple(i))
        else:
            l.append(list(i))
    return l if type(x) == tuple else tuple(l)

toggletype([(1,2,3),['ab','c'],["hello"]])
toggletype(([1,2,3],('ab','c'),("hello",)))
Out[5]:
[(1, 2, 3), ['ab', 'c'], ['hello']]
In [6]:
# lab validation code; do not modify
def labcheck(testing=0,ntest=10):
    '''
    Python exercise checking.
    Ed.Casas 2023-5-22
    Calls functions q<n>* and checks HMAC of return value[0].
    On mismatch prints return value[1] (function, arguments and return values).
    Setting testing=1 prints HMACs of correct results; paste into 'hashvalues'.
    Note:
    If q<n>* result not JSON-able, convert to string.
    Result order matters for comparison. Sort result if ordering not important.
    '''
    
    import base64, copy, hashlib, json, random, re, string, types 
    from random import randint
    
    # compare regex to strings that should/shouldn't match
    def checkre(pat,ok,nok):
        for s in ok:
            assert re.fullmatch(pat,s), \
                f"pattern '{pat}'\n did not match string '{s}'"
        for s in nok:
            assert not re.fullmatch(pat,s), \
                f"pattern '{pat}'\n matched string '{s}'"  
    
    # list of n words with nl letters from chars without repeats
    def randwords(n,chars=string.ascii_lowercase,nl=(2,5)):
        l = []
        while len(l)<n:
            w = ''.join([chars[randint(0,len(chars)-1)] for i in range(randint(*nl))])
            if w not in l:
                l.append(w)
        return l
    
    # convert sets to dicts and dict keys to strings so they can be sorted
    def orderkeys(o):
        if isinstance(o,set):
            return {str(k):None for k in o}
        if isinstance(o,dict):
            return {str(k):orderkeys(v) for k,v in o.items()}
        return o
    
    def Q1():
        s=randwords(1,nl=(5,8))[0]
        os=copy.deepcopy(s)
        l=substrings(s)
        return l,f"substrings({os}) returns {l}"

    def Q2():
        l = randwords(randint(5,8),nl=(2,5))
        p = [randint(0,1) for s in l]
        ol, op = copy.deepcopy(l), copy.deepcopy(p)
        r = reverseif(l,p)
        return r,f"reverserif({ol},{op}) returns {l}"

    def Q3():
        s = randwords(1,nl=(10,15))[0]
        x = randwords(1,nl=(10,15))[0]
        os, ox = copy.deepcopy(s), copy.deepcopy(x)
        r = removechars(s,x)
        return r,f"removechars({os},{ox}) returns {r}"
    
    def Q4():
        k=randwords(randint(2,4))+[randint(1,999) for i in range(randint(2,4))]
        random.shuffle(k)
        v=[[randint(-1,9) for i in range(randint(2,4))] for i in range(len(k))]
        v=[set(x) if randint(0,1) else x for x in v]
        d=dict(zip(k,v))
        od=copy.deepcopy(d)
        r = sumvalues(d)
        return r,f"sumvalues({od}) returns {r}"

    def Q5():
        l=[randwords(randint(2,3)) for l in range(randint(3,6))]
        l=[tuple(x) if randint(0,1) else x for x in l]
        l=tuple(l) if randint(0,1) else l
        ol=copy.deepcopy(l)
        r=toggletype(l)
        return r,f"toggletype({ol}) returns {r}"
   
    hashvalues = '''
N0seoh5a0d2KRdWGvbk3Z7anaQs6Ydfgm0C1MgQl
b8xYzKTFDNI/TovITOaltwp4nFejKrY25nPjnDVf
YPuAxb+6Bc80Hz5CGnFAMfmM+emnzb25X2GoLy7L
6wyDQqTOu5TI5VpYAS8Ch5RZfWLeT7lfkJXVR2cu
dEIzYl5qK7EWXFR5ixmkq2IwzIo8Q4tlQ+K9MlSB
'''.split()

    newhash = ''
    dsize = 3 # HMAC base64 digest size (bytes, use 3 or 6 for 4 or 8 char digests)
    dlen = ((dsize*8+5)//6+3)//4*4
           
    for n,f in [(n,f) for n,f in locals().items() if callable(f) and re.search(r'^[Qq]\d+.*',n)]:
        random.seed(n)      
        hashes = '0'*dlen*ntest if testing else hashvalues.pop(0)
        err = ''
        while hashes and not err:
            h, hashes = hashes[:dlen], hashes[dlen:] 
            try:
                v,s = f()
                b = json.dumps(orderkeys(v),sort_keys=True).encode()
                c = base64.b64encode(hashlib.blake2b(b,digest_size=dsize).digest()).decode()
                if testing:
                    print(s)
                    newhash += c
                else:
                    if c != h:
                        err = f"Wrong result for test {n}: {s} (HMAC={c} instead of {h})"
            except Exception as e:
                err = f"Error during test {n}: {e}"               
        if testing:
            newhash += '\n'
        else:
            print(err or f"Passed test {n}.")
            
    if testing:
        print(newhash)

labcheck()
Passed test Q1.
Passed test Q2.
Passed test Q3.
Passed test Q4.
Passed test Q5.