Question 1: Operation-inator

Dr. Doofenshmirtz is making a secret evil device that creates functions that do basic arithmetic operations using lambda functions. The operation-inator takes in an operation_string and returns a function that does that specific operation. The strings map to the functions like so:

  • "self" -> Return a function that takes an input and returns the exact same input without modifications
  • "add one" -> Return a function that takes in a number and returns the number + 1
  • "multiply together" -> Return a function that takes in 2 numbers and returns their product
  • "zero to self" -> Return a function that takes in a positive integer as input and returns a list of numbers that counts up by 1 from zero (inclusive) to the input (exclusive)

Help the good doctor implement his operation-inator by filling in the blanks with lambda functions.

See the doctests for more details.

def operation_inator(operation_string):
    >>> identity = operation_inator('self')
    >>> identity(5)
    >>> identity(6)
    >>> add_one = operation_inator('add one')
    >>> add_one(2)
    >>> add_one(3)
    >>> mul_together = operation_inator('multiply together')
    >>> mul_together(0, 1)
    >>> mul_together(3, 2)
    >>> zero_to_self = operation_inator('zero to self')
    >>> zero_to_self(3)
    [0, 1, 2]
    >>> zero_to_self(1)
    if operation_string == 'self':
        return lambda x: x
    elif operation_string == 'add one':
        return lambda x: x + 1
    elif operation_string == 'multiply together':
        return lambda x, y: x * y
    elif operation_string == 'zero to self':
        return lambda x: list(range(x))

Use OK to test your code:

python3 ok -q operation_inator

Question 2: Higher Order Lambdas

Return a lambda function that takes in a multiplier (the multiplier is a number) and returns a lambda function that will take in another number and will return the new input multiplied by the multiplier.

def higher_order_lambdas():
    Return a lambda function that takes in a multiplier and returns a lambda function that given an input will 
    return the input multiplied by the multiplier
    >>> hol = higher_order_lambdas()
    >>> doubles = hol(2)
    >>> doubles(3)
    >>> hol = higher_order_lambdas()
    >>> triples = hol(3)
    >>> triples(4)
    return lambda m : lambda n : m * n

Use OK to test your code:

python3 ok -q higher_order_lambdas

Question 3: Lambdas and Currying

We can transform multiple-argument functions into a chain of single-argument, higher order functions by taking advantage of lambda expressions. This is useful when dealing with functions that take only single-argument functions. We will see some examples of these later on.

Write a function lambda_curry2 that will curry any two argument function f2 using lambdas. See the doctest if you're not sure what this means.

def lambda_curry2(f2):
    Returns a Curried version of a two argument function func.
    >>> from operator import add, mul
    >>> x = lambda_curry2(add)
    >>> y = x(3)
    >>> y(5)
    >>> a = lambda_curry2(mul)
    >>> b = a(3)
    >>> b(5)
    return lambda arg1: lambda arg2: f2(arg1, arg2)

Use OK to test your code:

python3 ok -q lambda_curry2


Question 4: Replace All

Given a dictionary d, return a new dictionary where all occurences of x as a value (not a key) is replaced with y.

def replace_all(d, x, y):
    >>> d = {'foo': 2, 'bar': 3, 'garply': 3, 'xyzzy': 99}
    >>> e = replace_all(d, 3, 'poof')
    >>> e == {'foo': 2, 'bar': 'poof', 'garply': 'poof', 'xyzzy': 99}
    new = {}
    for key in d:
        if d[key] == x:
            new[key] = y
            new[key] = d[key]
    return new

Use OK to test your code:

python3 ok -q replace_all

Question 5: Lets Listen To...

Implement the function music_dict which takes in a dictionary where the keys are song titles and the value is the artist's name. The function music_dict returns a dictionary where each key is now the artist's name and the values are a list of all of the songs by that artist.

def music_dict(songs_dict):
    Returns a dictionary where each key is an artist name and the
    value is a list of all of the songs by that artist.

    >>> songs = {"Good Days": "SZA", "Karma": "Taylor Swift", "22": "Taylor Swift", "Snooze": "SZA", "vampire": "Olivia Rodrigo"}
    >>> music_dict(songs)
    {'SZA': ['Good Days', 'Snooze'], 'Taylor Swift': ['Karma', '22'], 'Olivia Rodrigo': ['vampire']}
    artist_songs = {}
    for song, artist in songs_dict.items():
        if artist in artist_songs:
            artist_songs[artist] = [song]
    return artist_songs

Use OK to test your code:

python3 ok -q music_dict

Question 6: Merge Dictionaries

Implement the function merge_dict. The merge_dict function merges two dictionaries with the same keys together by adding up their values for the corresponding keys and returning the resulting dictionary.

def merge_dict(dict1, dict2):
    """Returns a dictionary that is the result of two dictionaries being merged together. 
    Dictionaries are merged by adding up their values. You can assume that the same keys 
    appear in both dictionaries.
    >>> data8 = {"midterms":1, "projects":3}
    >>> data100 = {"midterms":2, "projects":3}
    >>> combined_exams = merge_dict(data8, data100)
    >>> combined_exams
    {'midterms': 3, 'projects': 6}
    >>> sunday_orders = {"pizza": 3, "hot dogs": 2, "fries": 5}
    >>> monday_orders = {"pizza": 1, "hot dogs": 1, "fries": 8}
    >>> combined_orders = merge_dict(sunday_orders, monday_orders)
    >>> combined_orders
    {'pizza': 4, 'hot dogs': 3, 'fries': 13}
    result_dict = {}
    for work in dict1:
        result_dict[work] = dict1[work] + dict2[work]
    return result_dict

Use OK to test your code:

python3 ok -q merge_dict