Section 7. Lambda, Map, Sorted, and Capstone Problems


Section materials written by Juliette Woodrow, Brahm Capoor, Anna Mistele, and John Dalloul


PyCharm Project



Reading map

Predict what each of the following blocks of code will do:

counting = [5, 6, 7, 8]
jenny = [8, 6, 7, 5, 3, 0]
lst = list(map(lambda lst: lst.append(9), [counting, jenny]))
counting = [5, 6, 7, 8]
jenny = [8, 6, 7, 5, 3, 0]
lst = list(map(lambda lst: lst + [9], [counting, jenny]))

Using map

Solve each of these problems using the map function described in lecture.

  • You and your freshman year roommate grew up in different countries. You often have trouble trying to explain the current temperature outside as one of you is familiar with degrees Celsius and the other is used to using degrees Fahrenheit. Fortunately, one of you is taking 106A and can help!

    Given a list of temperatures in degrees Farenheit like so:

temps_F = [45.7, 55.3, 62.1, 75.4, 32.0, 0.0, 100.0]

Write an expression to produce a list of those same temperatures, measured in degrees Celsius. As a reminder, to convert Farenheit to Celsius, you first subtract 32 and then multiply by 5/9.

  • You and some friends want to see what is going on at Cal before the big game. They might be planning something suspicous. To investigate, you plan to fly a drone over the football stadium in the days leading up to the game.

    Like any responsible drone pilot, you have plotted the flight path by writing down the direction, or heading, of the plane at each turn. An hour before the first takeoff, however, you realize that you didn't account for the magnetic deviation, or the local magnetic fields created by technology on the drone that mess with its internal compass reading. You also forgot to account for magnetic variation, or the difference between true north and magentic north. To account for magnetic deviation and variation, you must add 22 degrees to all of your heading calculations. Recall that the compass wraps around at 360 degrees, so any new heading calculated must also be between 0 and 359 degrees.

    Along with exact headings, you have also calculated if each turn is generally towards the North, East, South or West using the following buckets:

    • North: 316-45 degrees
    • East: 46-135 degrees
    • South: 136-225 degrees
    • West: 226-316 degrees

    Your job is to write an expression that given a list like so:

original_headings = [(30, 'N'), (359, 'N'), (340, 'N'), (270, 'W'), (124, 'E'), (149, 'S'), (219, 'S')]

Produces a new list with the updated headings and directions after correcting for magnetic variation and deviation. You may implement any helper functions you want, but your top-level expression should be one line of code.

  • The weather outside has been really beautiful lately, but when Chris went for his morning walk this morning, he got stung by a bee! To take retaliation against their species, he's jumbled up the script of the Bee Movie:
    s = """
    gnidroccA ot lla nwonk swal fo ,noitaiva ereht si on yaw a eeb dluohs eb 
    elba ot .ylf stI sgniw era oot llams ot teg sti taf elttil ydob ffo eht 
    .dnuorg ehT ,eeb fo ,esruoc seilf yawyna esuaceb seeb t'nod erac tahw snamuh 
    kniht si .elbissopmi
    """
    

    Chris took every word in the script, and reversed it! Write an expression to fix this, returning the first few lines of the Bee Movie script, in the correct order.

  • Given a vector (a list of numbers), return the result of performing a linear transformation on it. To perform the linear transformation, multiply each element of the vector by the given scale and add the given shift. For example, for vector a = [1, 2], scale = 5, and shift = 6, the function should return [1 * 5 + 6, 2 * 5 + 6] = [11, 16]. You may assume that the input vector only contains numbers and that the passed in scale and shfit values are also numbers. Use a lambda function to represent the transformation for each term of the vector and the map function to create the resulting vector.

  • Your friend, the chairman of the Kentucky Derby, has come to you with a problem: he has a list of times for the horses in terms of number of seconds for the 1.25 mile track, but now he wants the times in terms of how long it would take the horses to run a 100 yard dash. Write a function that takes the horses' times (in terms of # seconds / 1.25 miles) and returns the horses' 100 yard dash times (# seconds / 100 yards). Assume that the horses run at a constant speed and at the same pace as in their Kentucky Derby times. For reference, there are 1760 yards in 1 mile. Use your map lambda skills to fill in the convert_times(times) function.

Sorting with lambdas

Solve each of the following challenges in one line of Python, using the lambda technique:

  1. Given a list of strings strs, sort the list case-insensitively (i.e. ignoring whether the word is upper or lower case).

  2. Given a list of strings strs, sort the list according to the last character of each string, case-insensitively.

  3. Given a list of integers nums, sort the list according to the absolute difference between each number and 3.14. Python has an abs function, which takes as input a number and returns its absolute value, and which you might find helpful in this problem.

  4. Given a list of tuples that represents houses for rent, the number of bedrooms and their prices, like so:

    [('main st.', 4, 4000), ('elm st.', 1, 1200), ('pine st.', 2, 1600)]
    

    Sort the list in the following ways:

    a. In ascending order by number of rooms b. In ascending order of price c. In ascending order of price-per-room


Tweets Revisited

Recall the Big Tweets Data problem from last week, in which we worked with a user_tags dictionary whose keys were twitter usernames and whose values were additional nested dictionaries keeping track of the frequencies of Hashtag usage, like so:

user_tags = {'@alice': {'#apple': 1, '#banana': 2}, '@bob': {'#apple': 1}}

One of the suggested extensions for this problem was to implement a function called flat_counts, which takes in a user_tags and returns a dictionary that counts the number of times each Hashtag is used, across all users. For example, calling flat_counts and passing the user_tags dictionary in as a parameter would lead to the following behaviour:

>>> flat_counts(user_tags)
{'#apple': 2, '#banana': 2}

In Python, dictionaries have a built-in items() function that returns a list of (key, value) tuples.

  1. First, armed with the .items() function and your new toolkit for sorting, implement a function, reverse_alpha_keys(flat_counts), which given a flat_counts dictionary, prints out the hashtags in reverse aplphabetical order. Note that the sorted function will break ties using the next consecutive character in the string.
  2. Second, implement the following function: def most_used(flat_counts) which takes in a 'flat' dictionary as described above, and prints the 10 most frequently used hashtags in the dataset. With a solid understanding of how lambdas can be used in sorting, you should be able to solve this in just a few lines of code.

Final Review


We have provided a file for section/quiz review but you may notice that there are not written doctests or provided ways to test some of the functions. This is because we want to enourage you to study how you will write code on the final (without the immediate feedback of running your code). If you have questions about if your specific implementation will work, feel free to post on Ed or ask about in LaIR!

In addition to these problems, you can do additional practice problems on the experimental server as well as checkout all problems from the section 6 handout as well as all problems from the section 7 handout. We recommend that you try a problem before looking at the solution.


One Liners


  • Given list of non-empty strs, write a map/lambda and/or list comprehension to form a list of the strings in upper case.
            
>>> strs = ['Rhyme', 'Donut', '3xx', 'Orange']
# yields ['RHYME', 'DONUT', '3XX', 'ORANGE']
            
          
  • Given list of (x, y) points, write a sorted/lambda expression to order these points in decreasing order by the sum of the x+y of each point.
            
>>> points = [(10, 0), (1, 3), (3, 2), (5, 4)]
# yields [(10, 0), (5, 4), (3, 2), (1, 3)]
            
          

One lines from Quiz #3 Winter Quarter. You do not need to write a def for these questions. For each part, write a 1-line expression to compute the indicated value with: map() or sorted() or min() or max() or a comprehension. You do not need to call list() for these.

# a. Given a list of numbers.
# Call map() to produce a result where each
# number is multiplied by -1. (or equivalently write a comprehension)
>>> nums = [3, 0, -2, 5]
# yields [-3, 0, 2, -5]
# your expression:

pass



# b. Given a list of (x, y) "point" tuples where x and y are int values.
# Call map() to produce a result where each (x, y) is replaced
# by the sum of x and y. (or equivalently write a comprehension)
>>> points = [(1, 2), (4, 4), (1, 3)]
# yields [3, 8, 4]
# your expression:

pass




# c. Given a list of (city-name, zip-code, current-temperature) tuples, like this
>>> cities = [('modesto', 95351, 92), ('palo alto', 94301, 80), ...]
# Call sorted() to produce a list of these tuples sorted in decreasing
# order by temperature.
# your expression:

pass



# d. Given a non-empty list of (flower-name, scent-score, color-score) tuples
# like the following, scores are in the range 1 .. 10
>>> flowers = [('rose', 4, 8), ('orchid', 7, 2), ... ]
# Call max() or min() to return the flower tuple with the highest scent score.
# your expression:

pass


Capstone CS106A Problems

Dict File Problem from Winter Quarter Quiz #3

Suppose it is the year 2040, and the most important thing in the world is celebrities, each identified by a handle like '\@alice'. Celebrities post on the hot new social network PipPop. Each PipPop channel has a name like '#watsup' or '#meh'.

Given a text file with the following format: each line in the file represents one post by a celebrity to 1 or more channels. The first word on the line is a celebrity name like '\@alice', followed by 1 or more PipPop channel names, like this:

@alice^#meh^#wut

The line is divided into parts by '\^'. The celebrity and channel names may contain punctuation, but will not contain '\^'.

We'll say a "posts" dict has a key for each channel, and its value is a nested list of the celebrities that posted to that channel. The list of celebrities should not have duplicates in it; a celebrity should be in the list at most once.

{
...
'#meh': ['@juliette', '@arun', '@nick'],
'#texas': ['@miguel', '@rose'],
...
}

Write code to read through the file described above, building and returning the posts dict. The boilerplate code to read the files lines is provided, and you can change that code if you wish.

def read_posts(filename):
# your code here
pass

Prime File

The given file contains text data on each line as follows. Each line is made of a mixture of non-empty alphabetic words and non-negative ints, all separated by colons. The numbers can be distinguished since their first char is a digit. Lines like this: aaa:123:420:xyz:xxx:44:zz:a The first element is the "prime" for that line, and is always alphabetic. Implement a function, prime_file(filename) which reads through all the lines and builds a dictwith a key for each prime, and its value is a list of all the int number values from all the lines with that prime. Add every number to the list, even if it is a duplicate. When all the data is loaded, print the primes in alphabetical order 1 per line, each followed by its sorted list of numbers, like this aaa [44, 123, 123, 125, 420, 693] bbb [16, 23, 101, 101]

Dict File

Suppose you are part of a team handling a sudden surge of package deliveries. You have a data file for each day that looks like this:

ca,94301-0001,94025-1122,94301-9999,… wa,98001-0000,98001-4322,… …

The parts of each line are separated by commas. The first word is a 2-char state code. After the state are 1 or more zip+4 codes, like '94301-0001', each representing one delivery. The format of the zip+4 is: 5 digit zipcode, dash, 4 digits. We will treat the zipcode as a string.

Write code to build a "states" dict with a key for every state, The value for each state key is a nested dict which counts the number of times each zipcode string has a delivery, considering only the zipcode '94301' part of the zip+4 '94301-0001'.

    
{
'ca': {'94301': 2, '94025': 1, ...}
'wa': {'98001': 5, '98002': 1, ...}
}
    
  

Once the states dict is built, write code to print each state code on a line by itself, in increasing alphabetic order. Each state should be followed by its zip/count data, with the zipcodes in increasing order, so the overall print output looks like this:

ca 94025 1 94301 2 94563 5 tx 75001 5 75002 1 75011 2 wa 98001 5 98002 1

This function does not return anything - it prints its output. The standard code to open a file and loop over its lines is provided.

Lightning

There are many lightning strikes each day across the united states. Each lightning strike is represented by a number 1..100. Suppose you have a data file where each line represents one or more lightning events. Each line is made of one or more lightning strike ints followed by the state name, separated by commas like this:

26,1,ca
99,100,100,tx
12,50,ca
44,28,tx

Write a function to read the lines of this file and build a "states" dict with a key for each state, e.g. 'ca', and its value is a list of all that states's int strike numbers. So for example, the 4 lines of text above make this states dict:



{ 'ca': [26, 1, 12, 50],
'tx': [99, 100, 100, 44, 28],
}

When all the data is loaded, print the states in alphabetical order, 1 per line, each followed by its list of numbers, followed by the sum of the numbers, like this:

ak [100, 12] 112
ca [26, 1, 12, 50] 89
tx [99, 100, 100, 44, 28] 371
...

This function does not return anything - it prints its output. The standard code to open a file and loop over its lines is provided.


>>> # Reminder of how to print a list of ints:
>>> nums = [1, 2, 3]
>>> print(nums)
[1, 2, 3]

def parse_lightning(filename):
states = {}
with open(filename, 'r') as f:
    for line in f:
        pass