demographic_summary gives you every group. But your advisor wants only the top 5 groups by average satisfaction — and only from responses that have a valid satisfaction score. Right now, how would you build that filter?
Call filter_complete_responses, then demographic_summary, then sort. That's three calls and a loop I have to write myself.
responses_to_json from last week showed you how to serialise the output. Now list comprehensions collapse the filter step into one line. [r for r in responses if r.get("satisfaction") is not None] builds a new list with only the valid rows — no explicit loop, no append, no index:
responses = [{"year": "Junior", "satisfaction": 4.0}, {"year": "Senior"}]
valid = [r for r in responses if r.get("satisfaction") is not None]
print(valid) # [{'year': 'Junior', 'satisfaction': 4.0}][r for r in responses if ...] — it's the same as a for loop with an if inside, but written as one expression?
Exactly the same logic, half the lines. [expression for item in iterable if condition] is the template. The result is a new list containing only the items where the condition is True:
def top_groups_by_score(responses: list, field: str, n: int = 5) -> list:
"""Return top N groups by average satisfaction using a list comprehension filter."""
valid = [r for r in responses if r.get("satisfaction") is not None]
scored = score_per_response(valid)
summary = demographic_summary(valid, field)
ranked = sorted(summary.items(), key=lambda x: x[1]["avg_satisfaction"], reverse=True)
return [{"group": g, "avg_satisfaction": v["avg_satisfaction"], "count": v["count"]} for g, v in ranked[:n]]The comprehension filters, demographic_summary groups, sorted ranks — three tools, one pipeline, five lines.
Your advisor's top-five table is now a function argument change away from top-three or top-ten.
I used score_per_response from Week 2 inside this. That function is still doing its job three weeks later.
is not None is the correct check for explicit None values. if r.get("satisfaction") would also exclude 0.0 — a valid score that happens to be falsy. Always be explicit about what you're excluding.
[expression for item in iterable if condition]
Equivalent to:
result = []
for item in iterable:
if condition:
result.append(expression)Use comprehensions for simple filter/transform. Use explicit loops when you need side effects, multiple appends, or complex branching.
is not None vs truthiness0.0 is falsy but valid. if r.get("x") is not None includes 0.0; if r.get("x") does not.
[f(x) for row in matrix for x in row] iterates a 2D list. Keep nested comprehensions to two levels — three or more should become explicit loops for readability.
demographic_summary gives you every group. But your advisor wants only the top 5 groups by average satisfaction — and only from responses that have a valid satisfaction score. Right now, how would you build that filter?
Call filter_complete_responses, then demographic_summary, then sort. That's three calls and a loop I have to write myself.
responses_to_json from last week showed you how to serialise the output. Now list comprehensions collapse the filter step into one line. [r for r in responses if r.get("satisfaction") is not None] builds a new list with only the valid rows — no explicit loop, no append, no index:
responses = [{"year": "Junior", "satisfaction": 4.0}, {"year": "Senior"}]
valid = [r for r in responses if r.get("satisfaction") is not None]
print(valid) # [{'year': 'Junior', 'satisfaction': 4.0}][r for r in responses if ...] — it's the same as a for loop with an if inside, but written as one expression?
Exactly the same logic, half the lines. [expression for item in iterable if condition] is the template. The result is a new list containing only the items where the condition is True:
def top_groups_by_score(responses: list, field: str, n: int = 5) -> list:
"""Return top N groups by average satisfaction using a list comprehension filter."""
valid = [r for r in responses if r.get("satisfaction") is not None]
scored = score_per_response(valid)
summary = demographic_summary(valid, field)
ranked = sorted(summary.items(), key=lambda x: x[1]["avg_satisfaction"], reverse=True)
return [{"group": g, "avg_satisfaction": v["avg_satisfaction"], "count": v["count"]} for g, v in ranked[:n]]The comprehension filters, demographic_summary groups, sorted ranks — three tools, one pipeline, five lines.
Your advisor's top-five table is now a function argument change away from top-three or top-ten.
I used score_per_response from Week 2 inside this. That function is still doing its job three weeks later.
is not None is the correct check for explicit None values. if r.get("satisfaction") would also exclude 0.0 — a valid score that happens to be falsy. Always be explicit about what you're excluding.
[expression for item in iterable if condition]
Equivalent to:
result = []
for item in iterable:
if condition:
result.append(expression)Use comprehensions for simple filter/transform. Use explicit loops when you need side effects, multiple appends, or complex branching.
is not None vs truthiness0.0 is falsy but valid. if r.get("x") is not None includes 0.0; if r.get("x") does not.
[f(x) for row in matrix for x in row] iterates a 2D list. Keep nested comprehensions to two levels — three or more should become explicit loops for readability.
You are building the results section of your thesis and needs the top N demographic groups by average satisfaction — filtering out any responses without a satisfaction score first. Write `top_groups_by_score(responses, field, n=5)` that uses a list comprehension to filter valid responses, then returns the top N groups as a list of dicts with 'group', 'avg_satisfaction', and 'count'.
Tap each step for scaffolded hints.
No blank-editor panic.