runtime
58 / 250
lesson 58 Collection Algorithms · intermediate

Count, total and group by key

One pass over the records can build a dictionary keyed by category: orders per channel, revenue per state, order IDs per customer.

You'll be able to
  • Choose a key and a starting value (0 for counts and totals, an empty list for groups)
  • Create a key the first time it appears, then update it with += or append
  • Read the finished dictionary with items() to answer a question about it
The idea

Questions like *how many orders came from each channel?* need one answer per category, and you don't know the categories in advance. A dictionary fits: the key is the category, and the value is what you collect for it.

Every version of this pattern makes the same decision on each pass: is this key new? If it is, store a starting value: 0 for a count or a total, an empty list for a group. Then update the value stored under that key.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Orders per channel
channels = ["web", "app", "web", "phone", "app", "web"]
counts = {}
for channel in channels:
    if channel not in counts:
        counts[channel] = 0
    counts[channel] += 1
print(counts)
example-2.py · Forgetting the starting value
channels = ["web", "app"]
counts = {}
for channel in channels:
    counts[channel] += 1
print(counts)

The value can be a running total instead of a count: add the order's total instead of 1. Or it can be a list that you append to. A list per key is a group: every record that shares the key ends up together, in the order they were seen.

example-3.py · Order IDs per customer
def orders_by_customer(orders):
    groups = {}
    for order in orders:
        customer = order["customer_id"]
        if customer not in groups:
            groups[customer] = []
        groups[customer].append(order["order_id"])
    return groups

orders = [
    {"order_id": "O100282", "customer_id": "C00077"},
    {"order_id": "O100918", "customer_id": "C01338"},
    {"order_id": "O101219", "customer_id": "C00077"},
    {"order_id": "O101723", "customer_id": "C01338"},
    {"order_id": "O101777", "customer_id": "C00305"},
]
for customer, ids in orders_by_customer(orders).items():
    print(customer, len(ids), ids)

When to use it: any *per* question: per channel, per state, per product, per customer. Counts and totals use 0; groups use []. Mistake to avoid: creating the starting value on every pass instead of only the first. The concept check shows what that does.

Review
  • Pick the key (what you group by) and the starting value (0 for counts and totals, [] for groups).
  • On each pass: create the key if it is new, then update it with += or append.
  • d[k] += x reads the old value first, so a missing key raises KeyError.
  • Next: a dictionary keyed by ID can join two collections.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Count, total and group by key — Collection Algorithms · Runtime