Comprehensions Answers
Comprehension Exercises
Tip
Most of these you have seen before, and solved with for loops. You should use at least one list comprehension in each of these exercises! Each one can be tested by running python test.py function_name from your exercise directory.
Hint
If you get stuck for a minute or more, try searching Google or using help.
If you’re stuck for more than a few minutes, some of these links might be helpful for some of the exercises below:
Starting with a vowel
This is the get_vowel_names exercise in loops.py.
Edit the function get_vowel_names so that it accepts a list of names and returns a new list containing all names that start with a vowel. It should work like this:
>>> from loops import get_vowel_names
>>> names = ["Alice", "Bob", "Christy", "Jules"]
>>> get_vowel_names(names)
['Alice']
>>> names = ["Scott", "Arthur", "Jan", "elizabeth"]
>>> get_vowel_names(names)
['Arthur', 'elizabeth']
Answers
def get_vowel_names(names):
"""Return a list containing all names given that start with a vowel."""
return [
name
for name in names
if name[0].lower() in "aeiou"
]
Flatten a Matrix
This is the flatten exercise in loops.py.
Edit the function flatten, that will take a matrix (a list of lists) and return a flattened version of the matrix.
>>> from loops import flatten
>>> matrix = [[row * 3 + incr for incr in range(1, 4)] for row in range(4)]
>>> matrix
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
>>> flatten(matrix)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Answers
def flatten(matrix):
"""Return a flattened version of the given 2-D matrix (list-of-lists)."""
return [
item
for row in matrix
for item in row
]
Matrix From String
This is the matrix_from_string exercise that we’ve seen before in loops.py. The function accepts a string and returns a list of lists of integers (found in the string).
Refactor the function to use a list comprehension.
Example:
>>> from loops import matrix_from_string
>>> matrix_from_string("1 2\n10 20")
[[1, 2], [10, 20]]
Answers
def matrix_from_string(string):
"""Convert rows of numbers to list of lists."""
return [
[int(x) for x in row.split()]
for row in string.splitlines()
]
Power List By Index
This is the power_list exercise in ranges.py.
Edit the function, power_list, so that it accepts a list of numbers and returns a new list that contains each number raised to the i-th power where i is the index of that number in the given list. For example:
>>> from ranges import power_list
>>> power_list([3, 2, 5])
[1, 2, 25]
>>> numbers = [78, 700, 82, 16, 2, 3, 9.5]
>>> power_list(numbers)
[1, 700, 6724, 4096, 16, 243, 735091.890625]
Answers
def power_list(numbers):
"""Return a list that contains each number raised to the i-th power."""
return [n ** i for i, n in enumerate(numbers)]
Matrix Addition
This is the matrix_add exercise we saw earlier in ranges.py.
The function matrix_add accepts two matrices (lists of lists of numbers) and returns one matrix that includes each corresponding number in the two lists added together.
You should assume the lists of lists provided will always be the same size/shape.
Re-write the function to use list comprehensions.
>>> from ranges import matrix_add
>>> m1 = [[1, 2], [3, 4]]
>>> m2 = [[5, 6], [7, 8]]
>>> matrix_add(m1, m2)
[[6, 8], [10, 12]]
>>> m1 = [[1, 2, 3], [0, 4, 2]]
>>> m2 = [[4, 2, 1], [5, 7, 0]]
>>> matrix_add(m1, m2)
[[5, 4, 4], [5, 11, 2]]
Answers
def matrix_add(matrix1, matrix2):
"""Add corresponding numbers in given 2-D matrices."""
return [
[n + m for n, m in zip(row1, row2)]
for row1, row2 in zip(matrix1, matrix2)
]
Identity Matrix
This is the identity exercise in ranges.py.
Edit the identity function so that it takes as input a number size for the size of the matrix and returns an identity matrix of size x size elements.
An identity matrix is a square matrix with ones on the main diagonal and zeros elsewhere. A 3 by 3 identity matrix looks like:
identity_matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
The identity function should work like this:
>>> from ranges import identity
>>> identity(3)
[[1, 0, 0], [0, 1, 0], [0, 0, 1]]
>>> identity(4)
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
>>> identity(2)
[[1, 0], [0, 1]]
Answers
With a helper function for readability:
def same_value(x, y):
"""Returns 1 if x == y, else returns 0."""
if x == y:
return 1
else:
return 0
def identity(size):
"""Return an identity matrix of size x size."""
return [
[same_value(row, col) for row in range(size)]
for col in range(size)
]
Or, we could take advantage of the internal values of True and False. This is a legal and reasonable thing to do in Python!
def identity(size):
"""Return an identity matrix of size x size."""
return [
[int(row == col) for row in range(size)]
for col in range(size)
]
X marks the spot
This is the words_containing exercise in loops.py.
Edit the words_containing function so that it accepts a list of words and a letter and returns a list of all words in the string that contain the given letter.
Example:
>>> from loops import words_containing
>>> words_containing(['My', 'life', 'is', 'my', 'message'], 'y')
['My', 'my']
>>> words_containing(['My', 'life', 'is', 'my', 'message'], 'i')
['life', 'is']
>>> words_containing(['My', 'life', 'is', 'my', 'message'], 'm')
['My', 'my', 'message']
Answers
def words_containing(words, letter):
"""Return all words that contain the given letter."""
return [
word
for word in words
if letter in word.lower()
]
Pythagorean Triples
This is the triples exercise in ranges.py.
Edit the triples function so that it takes a number and returns a list of tuples of 3 integers where each tuple is a Pythagorean triple, and the integers are all less then the input number.
A Pythagorean triple is a group of 3 integers a, b, and c, such that they satisfy the formula a**2 + b**2 = c**2
>>> from ranges import triples
>>> triples(15)
[(3, 4, 5), (5, 12, 13), (6, 8, 10)]
>>> triples(30)
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12, 15), (10, 24, 26), (12, 16, 20), (15, 20, 25), (20, 21, 29)]
Answers
def triples(num):
"""Return list of Pythagorean triples less than input num"""
return [
(a, b, c)
for a in range(1, num)
for b in range(a+1, num)
for c in range(b+1, num)
if a**2 + b**2 == c**2
]
Generator Expression Exercises
Sum Timestamps
Let’s revisit the sum_timestamps exercise that we looked at in the “Loops” section.
Edit the function sum_timestamps in loops.py so that it takes a list of timestamp strings of “minute:seconds”, and returns a “minute:seconds” timestamp string that represents the total time from the list of timestamps.
Use a generator expression to sum the given timestamps.
Feel free to use the exercises parse_time and format_time from the “Function Exercises” section.
>>> from loops import sum_timestamps
>>> times = ["1:10", "0:12", "4:03", "2:45"]
>>> sum_timestamps(times)
'8:10'
>>> times = ["0:55", "0:55", "0:55", "0:55", "0:55"]
>>> sum_timestamps(times)
'4:35'
>>> sum_timestamps(["0:00"])
'0:00'
Here are the parse_time and format_time functions in case you need them:
def parse_time(time_string):
"""Return total seconds from string of minutes:seconds."""
sections = time_string.split(':')
return int(sections[0]) * 60 + int(sections[1])
def format_time(seconds):
"""Return a minutes:seconds string based on input seconds."""
sections = divmod(seconds, 60)
return f"{sections[0]}:{sections[1]:02d}"
Answers
def parse_time(time_string):
"""Return total seconds from string of minutes:seconds."""
sections = time_string.split(':')
return int(sections[0]) * 60 + int(sections[1])
def format_time(seconds):
"""Return a minutes:seconds string based on input seconds."""
sections = divmod(seconds, 60)
return f"{sections[0]}:{sections[1]:02d}"
def sum_timestamps(timestamps):
"""Return a timestamp that represents the sum of the input timestamps."""
return format_time(sum(
parse_time(time)
for time in timestamps
))
Join
Edit the function join in the generators.py file so it accepts an iterable and an optional sep argument and returns a string with all the objects in the iterable joined together (by the separator) into a new string.
>>> from generators import join
>>> join([3.5, 2.4, 6], sep=", ")
'3.5, 2.4, 6'
>>> join([1, 2, 3, 4], sep="\n")
'1\n2\n3\n4'
>>> print(join([1, 2, 3, 4], sep="\n"))
1
2
3
4
The separator (sep) should default to a space character.
>>> join([1, 2, 3, 4])
'1 2 3 4'
Answers
Using a generator expression (which converts each object to a string) passed to the string join method:
def join(iterable, sep=" "):
"""Join iterable of objects into a new string."""
return sep.join(
str(item)
for item in iterable
)
This solution allows the sep argument to be a non-string:
def join(iterable, sep=" "):
"""Join iterable of objects into a new string."""
return str(sep).join(
str(item)
for item in iterable
)
Strip Lines
Edit the function strip_lines in the generators.py file so that it accepts either a list of lines or a file object and returns an iterator of the same lines but with newline characters removed from the end of each line.
>>> from generators import strip_lines
>>> lines = ["line 1\n", "line 2\n"]
>>> list(strip_lines(lines))
['line 1', 'line 2']
For the bonus, make sure your strip_lines function accepts any iterable of lines and returns an iterator instead of a list. The returned iterator should loop over the given lines iterable lazily (it shouldn’t be looped over all at once).
>>> stripped_lines = strip_lines(["line 1\n", "line 2\n"])
>>> next(stripped_lines)
'line 1'
>>> next(stripped_lines)
'line 2'
Hint
Use the strip() method to remove newline characters, and create a generator expression or generator function to return an iterator that processes lines lazily.
Answers
Using a generator expression:
def strip_lines(lines):
"""Strip newline characters from the end of each line."""
return (line.rstrip('\n') for line in lines)
Using a generator function:
def strip_lines(lines):
"""Strip newline characters from the end of each line."""
for line in lines:
yield line.rstrip('\n')
Using the more general rstrip() method (removes all trailing whitespace):
def strip_lines(lines):
"""Strip newline characters from the end of each line."""
return (line.rstrip() for line in lines)
All Together
Edit the function all_together in the generators.py file so that it takes any number of iterables and returns a generator that yields their elements sequentially. Use a generator expression to do it.
Example:
>>> from generators import all_together
>>> list(all_together([1, 2], (3, 4), "hello"))
[1, 2, 3, 4, 'h', 'e', 'l', 'l', 'o']
>>> nums = all_together([1, 2], (3, 4))
>>> list(all_together(nums, nums))
[1, 2, 3, 4]
Answers
def all_together(*iterables):
"""String together all items from the given iterables."""
return (
item
for iterable in iterables
for item in iterable
)
Translate
This is the translate exercise we’ve seen before in dictionaries.py.
The function translate takes a string in one language and transliterates each word into another language, returning the resulting string.
Here is an (over-simplified) example translation dictionary you can use for translating from Spanish to English:
>>> words = {'esta': 'is', 'la': 'the', 'en': 'in', 'gato': 'cat', 'casa': 'house', 'el': 'the'}
Convert the translate function to use a generator comprehension. An example of how this function should work:
>>> from dictionaries import translate
>>> translate("el gato esta en la casa")
'the cat is in the house'
Answers
words = {
'esta': 'is',
'la': 'the',
'en': 'in',
'gato': 'cat',
'casa': 'house',
'el': 'the',
}
def translate(sentence):
"""Return a transliterated version of the given sentence."""
return " ".join(
words[w]
for w in sentence.split()
)
Parse Number Ranges
Edit the parse_ranges in the generators.py file so that it accepts a string containing ranges of numbers and returns a generator of the actual numbers contained in the ranges.
The range numbers are inclusive.
It should work like this:
>>> from generators import parse_ranges
>>> list(parse_ranges('1-2,4-4,8-10'))
[1, 2, 4, 8, 9, 10]
>>> list(parse_ranges('0-0, 4-8, 20-21, 43-45'))
[0, 4, 5, 6, 7, 8, 20, 21, 43, 44, 45]
Answers
def parse_ranges(ranges_string):
"""Return generator of numbers corresponding to ranges in a string"""
pairs = (
group.split('-')
for group in ranges_string.split(',')
)
return (
num
for start, stop in pairs
for num in range(int(start), int(stop)+1)
)
Find TODOs
This is the todos.py exercise in the modules directory. Create the file todos.py in the modules sub-directory of the exercises directory. To test it, run python test.py todos.py from your exercises directory.
Write a program that prints out every line in a file that contains the text TODO (I add TODO notes in my files to note to-dos I need to handle). Also print the line number before the line. The line numbers should be padded with zeros so that all the printed numbers are 3 digits long.
Example:
If workshop.rst contains:
This is how you make a list::
>>> numbers = [1, 2, 3]
.. TODO explain more about what lists are!
.. TODO add section on slicing
This is how you make a tuple::
>>> numbers = (1, 2, 3)
.. TODO explain more about tuples!
Running:
$ python todo.py workshop.rst
Should print out:
005 .. TODO explain more about what lists are!
007 .. TODO add section on slicing
013 .. TODO explain more about tuples!
Answers
import sys
filename = sys.argv[1]
with open(filename) as my_file:
todo_lines = (
(i, line.rstrip("\n"))
for i, line in enumerate(my_file, start=1)
if "TODO" in line
)
for i, line in todo_lines:
print(f"{i:03d}", line)
Primality
This is the is_prime exercise in ranges.py.
Edit the function is_prime so that it returns True if a number is prime and False otherwise.
Use a generator expression.
Example:
>>> from ranges import is_prime
>>> is_prime(21)
False
>>> is_prime(23)
True
Hint
You might want to use any or all for this.
Answers
def is_prime(candidate):
"""Return True if candidate number is prime."""
return candidate >= 2 and all(
candidate % n != 0
for n in range(2, candidate)
)
More performant:
from math import sqrt
def is_prime(candidate):
"""Return True if candidate number is prime."""
return candidate >= 2 and all(
candidate % n != 0
for n in range(2, int(sqrt(candidate))+1)
)
Sum All
This is the sum_all function in the loops.py file that is in the exercises directory.
Edit the function sum_all so that it accepts a list of lists of numbers and returns the sum of all of the numbers
Use a generator expression.
>>> from loops import sum_all
>>> matrix = [[1, 2, 3], [4, 5, 6]]
>>> sum_all(matrix)
21
>>> sum_all([[0, 1], [4, 2], [3, 1]])
11
Answers
With two loops:
Using the sum function and a loop:
def sum_all(number_lists):
"""Return the sum of all numbers in the given list-of-lists."""
total = 0
for numbers in number_lists:
total += sum(numbers)
return total
Using the sum function and a generator expression:
def sum_all(number_lists):
"""Return the sum of all numbers in the given list-of-lists."""
return sum(
n
for numbers in number_lists
for n in numbers
)
Deep Add
This is the deep_add exercise in exception.py.
Write a function deep_add that sums up all values given to it, including summing up the values of any contained collections.
>>> from exception import deep_add
>>> deep_add([1, 2, 3, 4])
10
>>> deep_add([(1, 2), [3, {4, 5}]])
15
Answers
With sum and a generator expression:
def deep_add(iterable_or_number):
"""Return sum of values in given iterable, iterating deeply."""
try:
numbers = (deep_add(x) for x in iterable_or_number)
except TypeError:
return iterable_or_number
else:
return sum(numbers)
Primes Over
Edit the function first_prime_over in the generators.py file so that it returns the first prime number over a given number.
Example:
>>> from generators import first_prime_over
>>> first_prime_over(1000000)
1000003
Answers
from math import sqrt
def is_prime(candidate):
"""Return True if candidate number is prime."""
return candidate >= 2 and all(
candidate % n != 0
for n in range(2, int(sqrt(candidate))+1)
)
def first_prime_over(n):
"""Return the first prime number over a given number."""
primes = (x for x in range(n+1, n**2) if is_prime(x))
return next(primes)
Head
This is the head exercise in generators.py.
Make a head function that lazily gives the first n items of a given iterable.
>>> numbers = [2, 1, 3, 4, 7, 11, 18, 29]
>>> squares = (n**2 for n in numbers)
>>> list(head(numbers, n=2))
[2, 1]
Note that your head function should not retrieve more than n items from the iterable.
For example here we partially-consume the squares generator object using head and then continue consuming it:
>>> numbers = [2, 1, 3, 4, 7, 11, 18, 29]
>>> squares = (n**2 for n in numbers)
>>> list(head(squares, 5))
[4, 1, 9, 16, 49]
>>> list(squares)
[121, 324, 841]
Answers
Calling next repeatedly:
def head(iterable, n):
"""Return first n items of a given iterable."""
iterator = iter(iterable)
return (next(iterator) for _ in range(n))
That solution would fail if n was greater than the number of items in the iterable (a RuntimeError would be raised).
Here’s a solution that works around that by using a sentinel value:
def head(iterable, n):
"""Return first n items of a given iterable."""
iterator = iter(iterable)
sentinel = object()
first_n = (
next(iterator, sentinel)
for _ in range(n)
)
return (
item
for item in first_n
if item is not sentinel
)
Total Air Travel
This is the total_air_travel.py exercise in the modules directory.
Note
If you’ve already solved this exercise, try to refactor it to use a generator expression.
Create the file total_air_travel.py in the modules sub-directory of the exercises directory. To test it, run python test.py total_air_travel.py from your exercises directory.
To test this manually, use the file expenses.csv.
Given a CSV file containing expenses by category, I’d like you to calculate how much money was spent on the category “Air Travel”.
The file is formatted like this:
Date,Merchant,Cost,Category
1/05/2017,American Airlines,519.25,Air Travel
1/12/2017,Southwest Airlines,298.90,Air Travel
1/17/2017,Mailchimp,19.80,Software
2/01/2017,Zapier,15.00,Software
2/05/2017,Lyft,24.24,Ground Transport
2/06/2017,Hattie Bs,18.13,Food
2/06/2017,Lyft,15.65,Ground Transport
The columns are:
The date of the expense
Merchant
Amount paid
Category
Your program should accept a single CSV file as input and it should print a floating point number representing the sum of the amounts paid for all “Air Travel” category expenses.
To test it manually, cd to the modules directory and run:
$ python total_air_travel.py expenses.csv
818.15
Answers
With csv.reader:
import csv
import sys
csv_filename = sys.argv[1]
with open(csv_filename) as csv_file:
reader = csv.reader(csv_file)
next(reader) # Skip headers
total = sum(
float(cost)
for date, merchant, cost, category in reader
if category == 'Air Travel'
)
print(total)
With csv.DictReader:
import csv
import sys
csv_filename = sys.argv[1]
with open(csv_filename) as csv_file:
reader = csv.DictReader(csv_file)
total = sum(
float(row['Cost'])
for row in reader
if row['Category'] == 'Air Travel'
)
print(total)
More Comprehension Exercises
Use some kind of comprehension to solve these exercises.
Flipped Dictionary
This is the flip_dict function in dictionaries.py.
Edit the function flip_dict, so that it flips dictionary keys and values, using a dictionary comprehension.
Example usage:
>>> from dictionaries import flip_dict
>>> flip_dict({'Python': "2015-09-15", 'Java': "2015-09-14", 'C': "2015-09-13"})
{'2015-09-15': 'Python', '2015-09-14': 'Java', '2015-09-13': 'C'}
Answers
def flip_dict(dictionary):
"""Return a new dictionary that maps the original values to the keys."""
return {v: k for k, v in dictionary.items()}
Interleave
Edit the interleave function in the ranges.py file so that it accepts two iterables and returns a list with the items in each iterable “interleaved” (item 0 from iterable 1, then item 0 from iterable 2, then item 1 from iterable 1, and so on). Assume the two lists have the same length.
To test it, run python test.py interleave in your exercises directory.
Example:
>>> from ranges import interleave
>>> interleave([1, 2, 3, 4], [5, 6, 7, 8])
[1, 5, 2, 6, 3, 7, 4, 8]
>>> interleave([1, 4, 7], [2, 5, 8])
[1, 2, 4, 5, 7, 8]
Answers
def interleave(iterable1, iterable2):
"""Return list of one item at a time from each given iterable."""
return [
item
for items in zip(iterable1, iterable2)
for item in items
]
ASCII Strings
This is the get_ascii_codes function in dictionaries.py.
Edit the function get_ascii_codes so that it accepts a list of strings and returns a dictionary containing the strings as keys and a list of corresponding ASCII character codes as values.
>>> from dictionaries import get_ascii_codes
>>> words = ["hello", "bye", "yes", "no", "python"]
>>> get_ascii_codes(words)
{'hello': [104, 101, 108, 108, 111], 'bye': [98, 121, 101], 'yes': [121, 101, 115], 'no': [110, 111], 'python': [112, 121, 116, 104, 111, 110]}
Answers
def get_ascii_codes(words):
"""Return a dictionary mapping the strings to ASCII codes."""
return {
word: [ord(c) for c in word]
for word in words
}
Double-valued Dictionary
This is the dict_from_truple exercise we’ve seen before in dictionaries.py. The function accepts a list of three-item tuples and returns a dictionary where the keys are the first item of each tuple and the values are a two-tuple of the remaining two items of each input tuple.
Re-write this function to use a dictionary comprehension.
Example usage:
>>> from dictionaries import dict_from_truple
>>> dict_from_truple([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
{1: (2, 3), 4: (5, 6), 7: (8, 9)}
Answers
def dict_from_truple(input_list):
"""Turn three-item tuples into a dictionary of two-valued tuples."""
return {
key: (value1, value2)
for key, value1, value2 in input_list
}
Factors
This is the get_all_factors function in dictionaries.py.
Edit the function get_all_factors so that it takes a set of numbers and makes a dictionary containing the numbers as keys and all factors as values.
>>> from dictionaries import get_all_factors
>>> get_all_factors({1, 2, 3, 4})
{1: [1], 2: [1, 2], 3: [1, 3], 4: [1, 2, 4]}
>>> get_all_factors({62, 293, 314})
{314: [1, 2, 157, 314], 293: [1, 293], 62: [1, 2, 31, 62]}
Hint
You can use this function to find the factors of any number:
def get_factors(number):
"""Return a list of all factors of the given number."""
return [
n
for n in range(1, number + 1)
if number % n == 0
]
Answers
def get_factors(number):
"""Return a list of all factors of the given number."""
return [
n
for n in range(1, number + 1)
if number % n == 0
]
def get_all_factors(numbers):
"""Return a dictionary mapping numbers to their factors."""
return {
n: get_factors(n)
for n in numbers
}
Multi-valued Dictionary
This is the dict_from_tuple exercise that we’ve seen before in dictionaries.py.
The function accepts a list of tuples of any length and returns a dictionary which uses the first item of each tuple as keys and all subsequent items as values.
Re-write this function to use a dictionary comprehension.
Example usage:
>>> from dictionaries import dict_from_tuple
>>> dict_from_tuple([(1, 2, 3, 4), (5, 6, 7, 8)])
{1: (2, 3, 4), 5: (6, 7, 8)}
>>> dict_from_tuple([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
{1: (2, 3), 4: (5, 6), 7: (8, 9)}
Answers
Using slicing:
def dict_from_tuple(input_list):
"""Turn multi-item tuples into a dictionary of multi-valued tuples."""
return {
items[0]: items[1:]
for items in input_list
}
Using * unpacking:
def dict_from_tuple(input_list):
"""Turn multi-item tuples into a dictionary of multi-valued tuples."""
return {
key: tuple(values)
for key, *values in input_list
}
Most common
This is the get_most_common exercise in sets.py.
Edit the function get_most_common so that it accepts any number of sets and returns a set of the most common items from each of the given sets.
For example:
>>> from sets import get_most_common
>>> get_most_common([{1, 2}, {2, 3}, {3, 4}])
{2, 3}
>>> restaurants_trey = {'Habaneros', 'Karl Strauss', 'Opera', 'Punjabi Tandoor'}
>>> restaurants_diane = {'Siam Nara', 'Punjabi Tandoor', 'Opera'}
>>> restaurants_peter = {'Karl Strauss', 'Opera', 'Habaneros'}
>>> get_most_common([restaurants_trey, restaurants_diane, restaurants_peter])
{'Opera'}
Answers
With a for loop
def get_most_common(sets):
"""Return a set of the most common items from each of the given sets."""
occurrences = {}
for s in sets:
for item in s:
occurrences.setdefault(item, 0)
occurrences[item] += 1
most = max(occurrences.values())
return {i for i, count in occurrences.items() if count == most}
Note that using a set and list.count is much less performant
def get_most_common(sets):
"""Return a set of the most common items from each of the given sets."""
items = [x for s in sets for x in s]
unique_items = set(items)
occurrences = {x: items.count(x) for x in unique_items}
most = max(occurrences.values())
return {i for i, count in occurrences.items() if count == most}
Sorted Dictionary
Edit the sort_dict function in dictionaries.py that takes an input dictionary and returns a new dictionary that is sorted by the keys.
Previously we created this function using for loops.
Now we want to refactor it to use a dictionary comprehension rather than for loops.
Review: Note that as of Python 3.6, dictionaries are “in order”. What this means is that when you iterate over a dictionary, the entries you get are in the order that they were added to the dictionary. They might not have been added to the dictionary in an ordering that is useful. Once we have a dictionary, we want to make a new dictionary that has all the same key-value pairs, but are in sorted order when it is iterated over.
Hint: Use the built-in function sorted.
To test with the automated tests, run python test.py sort_dict from the command line.
To test the function in the REPL, you can paste the function in from your text editor or import it as shown:
>>> from dictionaries import sort_dict
>>> my_dict = {1: 'one', 6: 'six', 4: 'four', 3: 'three', 2: 'two', 5: 'five'}
>>> new_dict = sort_dict(my_dict)
>>> new_dict
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six'}
Answers
def sort_dict(old_dict):
"""Return a new dictionary that is sorted."""
return {
key: old_dict[key]
for key in sorted(old_dict.keys())
}