You built campaigns_to_json — your list of campaign dicts is clean, structured, and ready to ship. Now the CMO wants the actual ranking: top five campaigns by lowest cost-per-lead, zero-lead entries excluded. In Excel, how would you filter before sorting?
campaigns_to_json gave me the final serialised output. For filtering — I'd use a helper column flagging leads > 0, then hide or delete those rows before sorting the CPL column ascending and keeping the top five.
That helper column is a list comprehension. One expression that filters and transforms in the same breath:
spends = [c["spend"] for c in campaigns if c.get("leads", 0) > 0]for c in campaigns is the loop. if c.get("leads", 0) > 0 is the filter. c["spend"] is what you keep. Python evaluates left to right — expression, then loop, then condition. Read it as: "give me the spend of every campaign where leads is greater than zero."
Wait — the expression comes before the loop? That feels backwards. I'd expect the condition first, then what to do with the result.
It clicks once you say it aloud: "give me c["spend"] for every c in campaigns if c.get("leads", 0) > 0". Same order as the English sentence. And c.get("leads", 0) is your IFERROR — if the "leads" key is missing, treat it as zero and filter it out anyway.
So the whole filter-and-extract is one line instead of initialising a list, writing a for loop, checking the condition, and appending. That's what the comprehension buys — no boilerplate.
Exactly. Your Week 2 self would have written four lines and felt good about it. Your Week 4 self writes one and moves on.
I can stack two comprehensions — one to filter, one to add CPL — then sort and slice. Let me try it:
def top_campaigns_by_cpl(campaigns: list, n: int = 5) -> list:
valid = [c for c in campaigns if c.get("leads", 0) > 0]
with_cpl = [{**c, "cpl": round(c["spend"] / c["leads"], 2)} for c in valid]
top = sorted(with_cpl, key=lambda c: c["cpl"])[:n]
print(f"Top {n} campaigns by CPL from {len(campaigns)} total")
return topThat's the pattern. {**c, "cpl": ...} spreads every existing field from c into a new dict and adds the computed cpl key — no manual field copying. sorted with key=lambda c: c["cpl"] sorts ascending, so the cheapest leads come first. The [:n] slice takes the top N. Three lines of real logic, no noise.
A list comprehension collapses init → loop → condition → append into one readable expression:
[expression for item in iterable if condition]
| Part | Role |
|---|---|
expression | what to keep / transform |
for item in iterable | the loop |
if condition | optional filter |
{**c, "cpl": value} copies all keys from c into a new dict and adds "cpl". Equivalent to dict(c) followed by d["cpl"] = value, but inline.
Use a comprehension when the logic fits in one line and reads clearly. Reach for an explicit loop when the body needs multiple steps or early returns.
You built campaigns_to_json — your list of campaign dicts is clean, structured, and ready to ship. Now the CMO wants the actual ranking: top five campaigns by lowest cost-per-lead, zero-lead entries excluded. In Excel, how would you filter before sorting?
campaigns_to_json gave me the final serialised output. For filtering — I'd use a helper column flagging leads > 0, then hide or delete those rows before sorting the CPL column ascending and keeping the top five.
That helper column is a list comprehension. One expression that filters and transforms in the same breath:
spends = [c["spend"] for c in campaigns if c.get("leads", 0) > 0]for c in campaigns is the loop. if c.get("leads", 0) > 0 is the filter. c["spend"] is what you keep. Python evaluates left to right — expression, then loop, then condition. Read it as: "give me the spend of every campaign where leads is greater than zero."
Wait — the expression comes before the loop? That feels backwards. I'd expect the condition first, then what to do with the result.
It clicks once you say it aloud: "give me c["spend"] for every c in campaigns if c.get("leads", 0) > 0". Same order as the English sentence. And c.get("leads", 0) is your IFERROR — if the "leads" key is missing, treat it as zero and filter it out anyway.
So the whole filter-and-extract is one line instead of initialising a list, writing a for loop, checking the condition, and appending. That's what the comprehension buys — no boilerplate.
Exactly. Your Week 2 self would have written four lines and felt good about it. Your Week 4 self writes one and moves on.
I can stack two comprehensions — one to filter, one to add CPL — then sort and slice. Let me try it:
def top_campaigns_by_cpl(campaigns: list, n: int = 5) -> list:
valid = [c for c in campaigns if c.get("leads", 0) > 0]
with_cpl = [{**c, "cpl": round(c["spend"] / c["leads"], 2)} for c in valid]
top = sorted(with_cpl, key=lambda c: c["cpl"])[:n]
print(f"Top {n} campaigns by CPL from {len(campaigns)} total")
return topThat's the pattern. {**c, "cpl": ...} spreads every existing field from c into a new dict and adds the computed cpl key — no manual field copying. sorted with key=lambda c: c["cpl"] sorts ascending, so the cheapest leads come first. The [:n] slice takes the top N. Three lines of real logic, no noise.
A list comprehension collapses init → loop → condition → append into one readable expression:
[expression for item in iterable if condition]
| Part | Role |
|---|---|
expression | what to keep / transform |
for item in iterable | the loop |
if condition | optional filter |
{**c, "cpl": value} copies all keys from c into a new dict and adds "cpl". Equivalent to dict(c) followed by d["cpl"] = value, but inline.
Use a comprehension when the logic fits in one line and reads clearly. Reach for an explicit loop when the body needs multiple steps or early returns.
Taylor's CMO wants the weekly CPL report to highlight the most efficient campaigns — lowest cost-per-lead — while excluding any campaign that drove zero leads (division by zero aside, zero-lead entries are just data noise). Write `top_campaigns_by_cpl(campaigns, n=5)` that takes a list of campaign dicts (each with `"name"`, `"spend"`, and `"leads"` keys) and returns the top `n` campaigns by lowest CPL. Use a list comprehension to filter out zero-lead campaigns, add a `"cpl"` key (rounded to 2 decimal places) to each surviving dict, sort ascending by CPL, and return the first `n` results. For example, `top_campaigns_by_cpl([{"name": "Email", "spend": 500.0, "leads": 10}, {"name": "Social", "spend": 1200.0, "leads": 0}], n=1)` should return `[{"name": "Email", "spend": 500.0, "leads": 10, "cpl": 50.0}]`.
Tap each step for scaffolded hints.
No blank-editor panic.