Syllabus Lesson 206 of 239 · Projects: Build Real Things
Projects: Build Real Things

Design It Yourself: A Daily Report

Every lesson up to now handed you a scaffold: a half-written function, a comment for each step, blanks to fill. Real work rarely arrives that way. Someone hands you a sentence -> "can you give me a daily summary of these events?" -> and the empty file is yours to fill. This lesson is that moment on purpose. The starter is almost blank: a signature and a docstring, nothing else. The skill being graded is not a new piece of syntax, it is turning a fuzzy ask into a working program.

The contract

Write daily_report(events). The input events is a list of dicts, each shaped like {"day": str, "type": str, "amount": number}. Return a dict that maps each day to a small summary of that day:

  • Every day that appears in the input is a key in the result, exactly once.
  • Each day maps to {"count": int, "total": number} where count is how many events fell on that day and total is the sum of their amount values.
  • An empty input list returns an empty dict {}.
  • If any event is missing one of the required keys (day, type, or amount), raise ValueError.

The order of the keys in the returned dict does not matter. What matters is that the counts and totals are right and every input day shows up once.

Three worked examples

daily_report([
    {"day": "Mon", "type": "coffee", "amount": 3},
    {"day": "Mon", "type": "lunch",  "amount": 12},
    {"day": "Tue", "type": "coffee", "amount": 4},
])
# -> {"Mon": {"count": 2, "total": 15},
#     "Tue": {"count": 1, "total": 4}}

daily_report([{"day": "Sat", "type": "movie", "amount": 20}])
# -> {"Sat": {"count": 1, "total": 20}}

daily_report([])
# -> {}

How to attack a blank page

When there is no scaffold, give yourself one in your head before you type. A reliable order:

  • Name the output shape. Here it is a dict keyed by day, each value a two-field dict. Picture one finished entry: "Mon": {"count": 2, "total": 15}. That single example tells you what every line of code is working toward.
  • Pick the structure that builds it. You are grouping rows by a key and accumulating two numbers per group. A dict that you update as you walk the list is the natural fit: the first time you see a day, start it at {"count": 0, "total": 0}; every time after, add to it.
  • Handle the edges before you celebrate. The empty list should fall out for free if you start from an empty dict and never special-case it. The malformed event is the one you have to choose to handle: check the keys are present and raise ValueError if not, rather than letting a KeyError leak out.

Notice there is no line-by-line comment telling you when to start a day or how to add to it. That decision is the exercise. Build the smallest thing that satisfies the contract, then read it back against the three examples above before you run it.

Your turn

Write daily_report(events) from the contract, with no scaffold to lean on. events is a list of dicts each shaped {"day": str, "type": str, "amount": number}. Return a dict mapping each day to {"count": int, "total": number}: count is how many events landed on that day, total sums their amounts, and every input day appears exactly once. An empty list returns {}. If any event is missing day, type, or amount, raise ValueError. Design the data shape and the loop yourself.

Spotted a problem in this lesson? Report it

Code · runs in your browser
Output