You want a single function that returns a complete picture: total spent, transaction count, average per transaction, and a per-category breakdown. All four facts, one dict. What pieces do you need?
Four accumulators. Total is sum of amounts. Count is len. Average is total divided by count. Category breakdown is the dict accumulator.
Exactly — you already have every pattern. This function is just about stacking them inside one body and returning one dict:
total = sum(t["amount"] for t in txns)
count = len(txns)sum(t["amount"] for t in txns) is a generator expression — same as a comprehension, different brackets. It hands sum() each amount one at a time without building the intermediate list.
And the by-category part is the dict accumulator from Week 3?
Exactly that — totals.get(cat, 0.0) + t["amount"] inside a for loop. Then you assemble everything into the return dict:
def summarize_expenses(txns):
if not txns:
return {"total": 0.0, "count": 0, "average": 0.0, "by_category": {}}
total = sum(t["amount"] for t in txns)
count = len(txns)
by_cat = {}
for t in txns:
by_cat[t["category"]] = by_cat.get(t["category"], 0.0) + t["amount"]
return {"total": total, "count": count, "average": round(total / count, 2), "by_category": by_cat}The empty-list guard returns all four keys with zeros. Is that better than returning None or an empty dict?
Much better. A caller that expects result["total"] should always find it — even when there's nothing to total. Consistent shape on the happy path and the edge path means no downstream if result is None: checks.
This is the biggest function I've written — but every piece of it is something I already know.
That's composition. Every week's patterns stack inside one function, each doing exactly the job it was trained for. No new syntax, just new arrangements.
TL;DR: every pattern from earlier weeks, stacked in one function, returning one dict.
sum(t["amount"] for t in txns) — generator expressionlen(txns) — countby_cat.get(cat, 0.0) + amountround(total / count, 2) — safe average at the return| Input | Returned shape |
|---|---|
| Non-empty | {total, count, average, by_category} |
| Empty | {total: 0.0, count: 0, average: 0.0, by_category: {}} |
Same keys, same types, every call. Callers never have to check for None.
You want a single function that returns a complete picture: total spent, transaction count, average per transaction, and a per-category breakdown. All four facts, one dict. What pieces do you need?
Four accumulators. Total is sum of amounts. Count is len. Average is total divided by count. Category breakdown is the dict accumulator.
Exactly — you already have every pattern. This function is just about stacking them inside one body and returning one dict:
total = sum(t["amount"] for t in txns)
count = len(txns)sum(t["amount"] for t in txns) is a generator expression — same as a comprehension, different brackets. It hands sum() each amount one at a time without building the intermediate list.
And the by-category part is the dict accumulator from Week 3?
Exactly that — totals.get(cat, 0.0) + t["amount"] inside a for loop. Then you assemble everything into the return dict:
def summarize_expenses(txns):
if not txns:
return {"total": 0.0, "count": 0, "average": 0.0, "by_category": {}}
total = sum(t["amount"] for t in txns)
count = len(txns)
by_cat = {}
for t in txns:
by_cat[t["category"]] = by_cat.get(t["category"], 0.0) + t["amount"]
return {"total": total, "count": count, "average": round(total / count, 2), "by_category": by_cat}The empty-list guard returns all four keys with zeros. Is that better than returning None or an empty dict?
Much better. A caller that expects result["total"] should always find it — even when there's nothing to total. Consistent shape on the happy path and the edge path means no downstream if result is None: checks.
This is the biggest function I've written — but every piece of it is something I already know.
That's composition. Every week's patterns stack inside one function, each doing exactly the job it was trained for. No new syntax, just new arrangements.
TL;DR: every pattern from earlier weeks, stacked in one function, returning one dict.
sum(t["amount"] for t in txns) — generator expressionlen(txns) — countby_cat.get(cat, 0.0) + amountround(total / count, 2) — safe average at the return| Input | Returned shape |
|---|---|
| Non-empty | {total, count, average, by_category} |
| Empty | {total: 0.0, count: 0, average: 0.0, by_category: {}} |
Same keys, same types, every call. Callers never have to check for None.
Write `summarize_expenses(txns)` that returns a dict with keys total (float), count (int), average (float, 2 decimals), by_category (dict). Empty input returns the zero-shape dict.
Tap each step for scaffolded hints.
No blank-editor panic.