Make it Concise
Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.
This week we've learned about ways to make code more concise (see sections on ternary statements, comprehensions, unpacking, and common operations here). Making code more concise can often help improve its clarity and reduce complexity, although there are certainly limits.
1) Refactoring Example
For example, consider the following program:
def calc_total(orders, costs):
"""
Given an orders dictionary mapping item (str) -> quantity (int) and a
costs dictionary mapping item (str) -> cost (float), find and return
the total cost of all the orders.
You may assume that orders and costs contain the same keys, and that all
the values are non-negative numbers.
"""
t = []
i = list(orders)
j = 0
while j < len(i):
k = i[j]
if orders[k] > 0 and costs[k] > 0:
t.append(orders[k] * costs[k])
j += 1
return sum(t)
print(calc_total({}, {}))
# expected 0
print(calc_total({'carrots': 5, 'strawberries': 1},
{'carrots': .1, 'strawberries': 3.25}))
# expected 3.75
One path to refactoring this code may look as follows:
# (removing docstrings and tests for concision)
def calc_total(orders, costs):
# original code, where do we even begin?
t = []
i = list(orders)
j = 0
while j < len(i):
k = i[j]
if orders[k] > 0 and costs[k] > 0:
t.append(orders[k] * costs[k])
j += 1
return sum(t)
def calc_total(orders, costs):
# first, let's use some better variable names
total_costs = []
items = list(orders)
i = 0
while i < len(items):
item = items[i]
if orders[item] > 0 and costs[item] > 0:
total_costs.append(orders[item] * costs[item])
i += 1
return sum(total_costs)
def calc_total(orders, costs):
# second, let's remove some unneeded code
total_costs = []
items = list(orders)
i = 0
while i < len(items):
item = items[i]
# if statement not needed, all values are non-negative!
total_costs.append(orders[item] * costs[item])
i += 1
return sum(total_costs)
def calc_total(orders, costs):
# third, let's write this in terms of a for loop instead of a while loop
total_costs = []
for item in orders:
total_costs.append(orders[item] * costs[item])
return sum(total_costs)
def calc_total(orders, costs):
# final one-line result: write a list comprehension
return sum([orders[item] * costs[item] for item in orders])
Note how we systematically made small changes (making lots of changes all at once is very prone to bugs!) While refactoring it is a good idea to frequently test your code after each small change to make sure that it still works as expected.
2) Refactoring Practice
To practice some of these skills, the following questions show correct functions written across multiple lines, with potentially bad code style. For each question, rewrite the function in one line. Partial credit will be awarded to functions that are correct and have improved style, but are not one line.
def combine_dicts(orders, costs):
"""
Given an orders dictionary mapping item (str) -> quantity (int) and a
costs dictionary mapping item (str) -> cost (float), find and return
a new dictionary mapping item -> (quantity, cost, total).
You may assume that orders and costs contain the same keys, and that all
the values are non-negative numbers.
"""
t = {}
i = list(orders)
j = 0
while j < len(i):
k = i[j]
t[k] = (orders[k], costs[k], orders[k] * costs[k])
j += 1
return t
print(combine_dicts({}, {}))
# expected: {}
print(combine_dicts({'carrots': 5, 'strawberries': 1},
{'carrots': .1, 'strawberries': 3.25}))
# expected: {'carrots': (5, 0.1, 0.5), 'strawberries': (1, 3.25, 3.25)}
def is_divisible(x, nums):
"""
Given an integer x, and a list of integers nums,
return whether all the nums are divisible by x.
You may assume that none of the numbers are 0.
"""
r = 0
i = -1
while i < len(nums) - 1:
i += 1
if nums[i] % x == 0:
r = r + 1
else:
r = r
if r == len(nums):
return True
else:
return False
print(is_divisible(5, [])) # expected True
print(is_divisible(4, [8, 15])) # expected False
print(is_divisible(3, [-12, 9, 6])) # expected True
print(is_divisible(2, [-12, 9, 6])) # expected False
def get_divisible(x, nums):
"""
Given an integer x, and a list of integers nums,
return a new list of nums that are evenly divisible by x.
You may assume that none of the numbers are 0.
"""
r = []
i = -1
while i < len(nums) - 1:
i += 1
if is_divisible(x, [nums[i]]):
r = r + [nums[i]]
else:
r = r
return r
print(get_divisible(5, []))
# expected []
print(get_divisible(5, list(range(1, 20))))
# expected [5, 10, 15]
print(get_divisible(2, [i for i in range(10, 100, 5)]))
# expected [10, 20, 30, 40, 50, 60, 70, 80, 90]
Next Exercise: Survey