Skip to content

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:

data = [("101", 85), ("102", 75), ("103", 45), ("104", 95), ("105", 35)]

Average = (85 + 75 + 45 + 95 + 35) / 5 = 335 / 5 = 67.0

Expected outputs:

criteria
'above_average'
Output
["101", "102", "104"]
criteria
'fail'
Output
["105"]
criteria
'toppers'
Output
["104"]
criteria
None
Output
["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

01

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.

02

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.

03

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.