← Gym/Event Counter
00:00/ 12 min

🧭 Do not search for the first 15 minutes. When stuck: re-read the requirements → define I/O → choose the data structure → trace a small example by hand → write code.

You are given a log of user actions. Each line records that someone did something, and the same person may do the same thing many times.

Implement count_events(events), which counts how many times each user performed each event. A warm-up problem for getting your hands back on nested dictionaries.

Input

python
events = [
    ("alice", "login"),
    ("bob", "login"),
    ("alice", "purchase"),
    ("alice", "login"),
    ("bob", "logout"),
]
  • Each entry is a (user, event) pair.
  • User names and event names are arbitrary strings. The empty string is allowed.
  • The same (user, event) pair may appear many times.

Output

Return a nested dictionary whose outer key is the user, inner key the event, and value the count.

python
count_events(events)
# {
#     "alice": {"login": 2, "purchase": 1},
#     "bob": {"login": 1, "logout": 1},
# }

Following the input one line at a time:

  • ("alice", "login"): alice is new. Create her counter and set login to 1.
  • ("bob", "login"): bob is new too. Create his counter and set login to 1.
  • ("alice", "purchase"): alice's counter already exists. Add purchase as 1.
  • ("alice", "login"): alice's login is already 1, so it becomes 2.
  • ("bob", "logout"): add logout as 1 to bob's counter.

Order of the keys

Keys at both levels keep their order of first appearance.

In the example the outer keys are alice then bob. That is because alice appeared first, not because the names were sorted. The same goes for alice's inner keys being login then purchase.

Python dictionaries remember insertion order. Assigning to a key that already exists does not move it to the back. So inserting in the order things appear is all this rule requires.

Things to watch

  1. A combination that never occurred is not stored, not even as a zero. If bob never made a purchase, his dictionary must not contain a purchase key at all.
  2. Counters must not leak between users. alice's login and bob's login are separate values.
  3. The empty string is a valid key. An entry of ("", "") counts the empty-string event for the empty-string user.
  4. Empty input returns an empty dictionary.

Level 1 · Nested aggregation

Implement count_events(events).

  • User and event names are arbitrary strings (the empty string is possible too).
  • If the same (user, event) pair appears more than once, accumulate it that many times.