S3Q1 · Student Marks Filter¶
⚡ Quick Reference
Function: get_roll_nos(data: list, criteria=None)
Core idea: compute the average, then dispatch based on the criteria string.
def get_roll_nos(data: list, criteria=None):
avg = sum(m for _, m in data) / len(data)
filters = {
'above_average': lambda m: m >= avg,
'below_average': lambda m: m < avg,
'fail': lambda m: m < 40,
'toppers': lambda m: m >= 90,
None: lambda m: True,
}
if criteria not in filters:
return None
return [r for r, m in data if filters[criteria](m)]
Key rules:
- above_average → >= avg (inclusive)
- below_average → < avg (strict)
- fail → < 40
- toppers → >= 90
- None → all roll numbers
- Any other value → return None
Problem Statement¶
Problem
Write a function get_roll_nos(data, criteria=None) that filters student roll numbers from a list of (rollno, marks) tuples based on the given criteria. Preserve the original order.
Sample data:
Average = (85 + 75 + 45 + 95 + 35) / 5 = 335 / 5 = 67.0
Expected outputs:
'above_average'
["101", "102", "104"]
'fail'
["105"]
'toppers'
["104"]
None
["101", "102", "103", "104", "105"]
Breaking down each criteria¶
| Criteria | Condition | Students from sample |
|---|---|---|
above_average |
marks >= 67.0 |
101(85), 102(75), 104(95) |
below_average |
marks < 67.0 |
103(45), 105(35) |
fail |
marks < 40 |
105(35) |
toppers |
marks >= 90 |
104(95) |
None |
all | all five |
| anything else | - | return None |
None as a valid dict key
Python dictionaries can use None as a key. Including None: lambda m: True in the dispatch dict means the None criteria (return all) is handled identically to the others - no special case needed.
Complete solution approaches¶
def get_roll_nos(data: list, criteria=None):
avg = sum(m for _, m in data) / len(data)
filters = {
'above_average': lambda m: m >= avg,
'below_average': lambda m: m < avg,
'fail': lambda m: m < 40,
'toppers': lambda m: m >= 90,
None: lambda m: True,
}
if criteria not in filters:
return None
return [r for r, m in data if filters[criteria](m)]
Lambda dispatch - each criteria maps directly to its condition. The None key handles the "return all" case.
def get_roll_nos(data: list, criteria=None):
avg = sum(m for _, m in data) / len(data)
if criteria == 'above_average':
return [r for r, m in data if m >= avg]
elif criteria == 'below_average':
return [r for r, m in data if m < avg]
elif criteria == 'fail':
return [r for r, m in data if m < 40]
elif criteria == 'toppers':
return [r for r, m in data if m >= 90]
elif criteria is None:
return [r for r, _ in data]
else:
return None
Each case explicit - easiest to read and debug.
def get_roll_nos(data: list, criteria=None):
avg = sum(m for _, m in data) / len(data)
conditions = {
'above_average': lambda m: m >= avg,
'below_average': lambda m: m < avg,
'fail': lambda m: m < 40,
'toppers': lambda m: m >= 90,
None: lambda m: True,
}
if criteria not in conditions:
return None
cond = conditions[criteria]
return list(map(
lambda t: t[0],
filter(lambda t: cond(t[1]), data)
))
filter(lambda t: cond(t[1]), data) selects qualifying tuples. map(lambda t: t[0], ...) extracts roll numbers. Fully functional pipeline.
Key takeaways¶
None as a dict key
None is a valid Python dict key. Using it in a dispatch dictionary avoids a special case for the "return all" criteria - it's just another entry in the dict.
criteria not in filters → return None
The unknown-criteria guard comes before using the dict. Check membership first, then look up safely - avoids a KeyError on invalid input.
Compute average once, reuse in lambdas
The lambdas for above_average and below_average close over avg - they capture it from the enclosing function scope. No need to pass avg as an argument.