Last week Harper used a while loop to keep reading spend rows until the budget ran out. Today the data is already in memory — a list of campaign dicts — but the CMO wants it reorganised: one bucket per channel. In Excel, what's the tool?
A pivot table — drag channel to Rows, name to Values, and it groups everything automatically. I do this every Monday.
A dictionary is Python's pivot engine. You build it once, key by channel, and each key holds a list of matching campaigns. The secret weapon is .setdefault(): if the key already exists it hands you the list; if it doesn't, it creates an empty one first — then you append:
result = {}
for c in campaigns:
result.setdefault(c["channel"], []).append(c)Wait — .setdefault() returns the list? I expected it to just set the default silently, like a config call. Why does it return anything?
That return value is the whole trick. It gives back the existing list or the newly created one, so you can chain .append() on the same line without a separate if block. One line does what four would otherwise:
if "email" not in result:
result["email"] = []
result["email"].append(c) # four lines collapsed to oneSo .setdefault() is like a "get or create" — it never overwrites an existing key, and it gives me something to act on immediately.
Exactly. Your pivot table button has been lying to you — this is all it ever did under the hood. Once the loop ends, result.keys() shows your channels, result.values() shows your campaign lists, and result.items() lets you iterate both at once if you need to print a summary.
And the insertion order is preserved in Python 3.7+, so the output channels appear in the same sequence they showed up in the raw data — no surprise reordering.
That matters more than people realise. A report that reorders channels silently is a report that gets questioned in the meeting. Rely on insertion order deliberately, and your output is reproducible every time the input is the same.
A dictionary maps keys to values. .setdefault(key, default) returns the value for key if it exists; otherwise inserts default and returns it — enabling the get-or-create pattern in one expression.
| Method | Returns |
|---|---|
d[key] | Value — raises KeyError if missing |
d.get(key, fallback) | Value or fallback — never raises |
d.setdefault(key, []) | Existing or new value |
d.keys() | All keys (view) |
d.values() | All values (view) |
d.items() | (key, value) pairs |
Using d[key] instead of .get() or .setdefault() raises KeyError on the first unseen channel. Always guard with .get() or .setdefault().
Last week Harper used a while loop to keep reading spend rows until the budget ran out. Today the data is already in memory — a list of campaign dicts — but the CMO wants it reorganised: one bucket per channel. In Excel, what's the tool?
A pivot table — drag channel to Rows, name to Values, and it groups everything automatically. I do this every Monday.
A dictionary is Python's pivot engine. You build it once, key by channel, and each key holds a list of matching campaigns. The secret weapon is .setdefault(): if the key already exists it hands you the list; if it doesn't, it creates an empty one first — then you append:
result = {}
for c in campaigns:
result.setdefault(c["channel"], []).append(c)Wait — .setdefault() returns the list? I expected it to just set the default silently, like a config call. Why does it return anything?
That return value is the whole trick. It gives back the existing list or the newly created one, so you can chain .append() on the same line without a separate if block. One line does what four would otherwise:
if "email" not in result:
result["email"] = []
result["email"].append(c) # four lines collapsed to oneSo .setdefault() is like a "get or create" — it never overwrites an existing key, and it gives me something to act on immediately.
Exactly. Your pivot table button has been lying to you — this is all it ever did under the hood. Once the loop ends, result.keys() shows your channels, result.values() shows your campaign lists, and result.items() lets you iterate both at once if you need to print a summary.
And the insertion order is preserved in Python 3.7+, so the output channels appear in the same sequence they showed up in the raw data — no surprise reordering.
That matters more than people realise. A report that reorders channels silently is a report that gets questioned in the meeting. Rely on insertion order deliberately, and your output is reproducible every time the input is the same.
A dictionary maps keys to values. .setdefault(key, default) returns the value for key if it exists; otherwise inserts default and returns it — enabling the get-or-create pattern in one expression.
| Method | Returns |
|---|---|
d[key] | Value — raises KeyError if missing |
d.get(key, fallback) | Value or fallback — never raises |
d.setdefault(key, []) | Existing or new value |
d.keys() | All keys (view) |
d.values() | All values (view) |
d.items() | (key, value) pairs |
Using d[key] instead of .get() or .setdefault() raises KeyError on the first unseen channel. Always guard with .get() or .setdefault().
Harper's analytics dashboard needs campaigns grouped by channel so each team lead sees only their own data. Write `group_by_channel(campaigns)` that takes a list of campaign dicts (each with at least `"name"` and `"channel"` keys) and returns a dict mapping each channel string to the list of campaign dicts that belong to it, preserving the original order within each channel.
Tap each step for scaffolded hints.
No blank-editor panic.