The collections module
You have met Counter. The rest of collections holds more containers for jobs that plain lists and dicts do awkwardly.
from collections import (
Counter, defaultdict, deque, namedtuple)
stock = Counter(apple=3, pear=1)
sold = Counter(apple=1, pear=2)
print(stock - sold, stock + sold)
spent = defaultdict(int)
orders = [("ann", 5), ("bo", 2), ("ann", 1)]
for name, amount in orders:
spent[name] += amount
print(dict(spent))
recent = deque("abcde", maxlen=3)
recent.appendleft("z")
print(recent)
Point = namedtuple("Point", "x y")
p = Point(1, 2)
print(p.x, p._replace(y=5), p._asdict())- Counters add and subtract, and the result drops any count that falls to zero or below, which suits stock and shopping lists.
defaultdictcalls its factory for a missing key:intgives 0 for totals,listan empty group,setan empty set.dequeadds and removes at both ends in constant time, wherelist.pop(0)shifts every item. Withmaxlen, items fall off the far end.namedtupleis a tuple with field names._replacereturns a changed copy and_asdicta dict.
Your task
Write shortfall(needed, have) returning a dict of how many of each item in the list needed are still missing after using the list have, with no zero entries. Write totals(pairs) summing the amounts of (name, amount) pairs per name into a plain dict. Write tail(items, n) returning the last n items of any iterable as a list. Define Card = namedtuple("Card", "rank suit").
The explanation opens here once every check passes.