Last week is_valid_response told you whether a single response passed validation. Now you have 500 of them in a list. How do you separate the valid ones from the invalid ones without calling is_valid_response 500 times manually?
Loop over them and add the valid ones to a new list? But I haven't done loops yet — I'm not sure how to build that.
You already have the logic. A Python list is like your class roster — 500 rows, each a dict. append adds one item. len tells you how many. in checks membership. The loop is just a structure that runs a block of code once per row:
responses = [{"major": "Bio", "satisfaction": "4"}, {"major": ""}]
required = ["major", "satisfaction"]
valid = []
for r in responses:
if is_valid_response(r, required):
valid.append(r)
print(f"Valid: {len(valid)} of {len(responses)}")for r in responses — so r is each dict, one at a time? It's not the index?
Exactly. Python loops over the items directly — r is the dict itself, not the row number. You don't need an index to access elements unless you explicitly want the position. This is the loop pattern that replaces clicking through 500 rows:
def filter_complete_responses(responses: list, required_fields: list) -> list:
valid = []
for r in responses:
if is_valid_response(r, required_fields):
valid.append(r)
print(f"Kept {len(valid)} of {len(responses)} responses")
return validI call this once and get back a clean list — no pivot, no helper column, no filter step to redo.
And is_valid_response from Week 1 does the actual checking. You're not rewriting logic — you're composing functions.
I built is_valid_response as a standalone tool and now it slots straight into this pipeline. That's what reusable code actually means.
Never mutate the original list. The valid = [] + append pattern builds a new list and leaves the source untouched. If you loop over responses and modify it while iterating, you'll get unpredictable results — always build a new list.
A Python list holds items in order: responses = [{...}, {...}]. Key operations:
| Operation | Effect |
|---|---|
list[0] | Access first item |
len(list) | Number of items |
list.append(x) | Add x at the end |
x in list | Check membership |
for item in collection: iterates over every item — item is the value itself, not the index. Indent the loop body four spaces.
Last week is_valid_response told you whether a single response passed validation. Now you have 500 of them in a list. How do you separate the valid ones from the invalid ones without calling is_valid_response 500 times manually?
Loop over them and add the valid ones to a new list? But I haven't done loops yet — I'm not sure how to build that.
You already have the logic. A Python list is like your class roster — 500 rows, each a dict. append adds one item. len tells you how many. in checks membership. The loop is just a structure that runs a block of code once per row:
responses = [{"major": "Bio", "satisfaction": "4"}, {"major": ""}]
required = ["major", "satisfaction"]
valid = []
for r in responses:
if is_valid_response(r, required):
valid.append(r)
print(f"Valid: {len(valid)} of {len(responses)}")for r in responses — so r is each dict, one at a time? It's not the index?
Exactly. Python loops over the items directly — r is the dict itself, not the row number. You don't need an index to access elements unless you explicitly want the position. This is the loop pattern that replaces clicking through 500 rows:
def filter_complete_responses(responses: list, required_fields: list) -> list:
valid = []
for r in responses:
if is_valid_response(r, required_fields):
valid.append(r)
print(f"Kept {len(valid)} of {len(responses)} responses")
return validI call this once and get back a clean list — no pivot, no helper column, no filter step to redo.
And is_valid_response from Week 1 does the actual checking. You're not rewriting logic — you're composing functions.
I built is_valid_response as a standalone tool and now it slots straight into this pipeline. That's what reusable code actually means.
Never mutate the original list. The valid = [] + append pattern builds a new list and leaves the source untouched. If you loop over responses and modify it while iterating, you'll get unpredictable results — always build a new list.
A Python list holds items in order: responses = [{...}, {...}]. Key operations:
| Operation | Effect |
|---|---|
list[0] | Access first item |
len(list) | Number of items |
list.append(x) | Add x at the end |
x in list | Check membership |
for item in collection: iterates over every item — item is the value itself, not the index. Indent the loop body four spaces.
Daniel is preparing your thesis survey data for analysis. He has a list of response dicts and needs to filter out any rows with missing or empty required fields before computing demographics. Write `filter_complete_responses(responses, required_fields)` that returns a new list containing only the responses that pass `is_valid_response`.
Tap each step for scaffolded hints.
No blank-editor panic.