contentintech
Learn/Fresher SDE Preparation/Functions and collections
Beginner~5 min read + exercises

Functions and collections — build a useful script

Function contracts, lists, sets, dictionaries, exceptions and JSON persistence with a tested expense-summary exercise.

PythonFunctionsCollections

Write a contract before a function

A function has inputs, a result and rules about invalid inputs. “Summarize expenses” is too vague. A better contract is: receive non-negative integer amounts in paise and a non-negative budget; return the total, largest amount or None if empty, and a boolean indicating whether total exceeds budget.

Use functions to separate calculation from reading files and printing. Pure calculations are easier to test because the same inputs produce the same result without external effects.

Choose the collection that matches the question

CollectionUse whenExample
ListOrder and duplicates matterExpenses in entry order
SetMembership or uniqueness mattersUnique categories
DictionaryLook up a value by keyCategory totals
TupleA fixed grouping of valuesHours and leftover minutes

A set does not preserve a sorted order for presentation. Sort it explicitly. Dictionary lookup is expected O(1), not an unconditional worst-case guarantee. A nested loop over all pairs is usually O(n²); replacing repeated searches with a set can reduce work when extra memory is acceptable.

Worked expense summary

python
def summarize_expenses(amounts, budget):
    if not isinstance(budget, int) or isinstance(budget, bool) or budget < 0:
        raise ValueError("Budget must be a non-negative integer")
    total = 0
    largest = None
    for amount in amounts:
        if not isinstance(amount, int) or isinstance(amount, bool) or amount < 0:
            raise ValueError("Expenses must be non-negative integers")
        total += amount
        if largest is None or amount > largest:
            largest = amount
    return {"total": total, "largest": largest, "over_budget": total > budget}

assert summarize_expenses([], 0) == {
    "total": 0, "largest": None, "over_budget": False
}
assert summarize_expenses([120, 80], 200)["over_budget"] is False
assert summarize_expenses([120, 80], 199)["over_budget"] is True

Python booleans are instances of integer, so the additional boolean check is intentional. This function processes n expenses in O(n) time and keeps O(1) additional state. The return dictionary has a fixed number of fields.

python
def totals_by_category(records):
    totals = {}
    for category, amount in records:
        if amount < 0:
            raise ValueError("Amount must be non-negative")
        totals[category] = totals.get(category, 0) + amount
    return totals

assert totals_by_category([
    ("food", 100), ("travel", 50), ("food", 75)
]) == {"food": 175, "travel": 50}

A missing key is different from a key with a value of zero. get(category, 0) supplies a starting total for this specific operation. Do not apply default values mechanically to identifiers or missing required fields.

Mutation and shared references

python
original = [1, 2]
alias = original
copy = original.copy()
alias.append(3)
assert original == [1, 2, 3]
assert copy == [1, 2]

Assignment does not copy a list. A shallow copy makes a new outer list but still shares nested mutable objects. Before modifying input, decide whether your contract allows it. In interviews, state whether the solution changes the input.

Avoid a mutable default argument. Prefer items=None and create the list inside the function. Default objects are evaluated once when the function is defined, not freshly for every call.

Persist data in a local file

The following file-writing example runs locally, not in every browser sandbox. Place it in a temporary practice folder. It stores non-sensitive exercise data; do not put passwords or tokens in this file.

python
import json
from pathlib import Path

path = Path("expenses.json")
records = [{"category": "food", "amount": 120}]
path.write_text(json.dumps(records), encoding="utf-8")
loaded = json.loads(path.read_text(encoding="utf-8"))
assert loaded == records

Reading may fail because the file is missing, inaccessible or malformed. Catch the exception you can meaningfully handle. Catching every exception and returning an empty list would make corrupted data look like no expenses. Production multi-user storage also needs concurrency control and access rules; a local JSON file is a learning step, not a database substitute.

Practice with answers

Task A: Return unique lowercase email strings from a list, preserving the first occurrence. For this exercise, normalize by stripping whitespace and lowercasing; this is a simplified product rule, not a universal statement about email identity.

python
def unique_emails(emails):
    result = []
    seen = set()
    for email in emails:
        normalized = email.strip().lower()
        if normalized not in seen:
            seen.add(normalized)
            result.append(normalized)
    return result

assert unique_emails([" A@example.com ", "a@example.com", "b@example.com"]) == [
    "a@example.com", "b@example.com"
]

Task B: Find the most frequent category. If frequencies tie, return the lexicographically smallest category; return None on empty input.

python
def most_frequent(categories):
    counts = {}
    for category in categories:
        counts[category] = counts.get(category, 0) + 1
    if not counts:
        return None
    return min(counts, key=lambda category: (-counts[category], category))

assert most_frequent(["travel", "food", "travel", "food"]) == "food"
assert most_frequent([]) is None

The tie rule is part of the specification. Without it, two correct-looking implementations could disagree. Explain the O(n + k) expected time, where k is the number of distinct categories.

Checkpoint

Build a small command-line expense report that reads JSON, validates required fields, prints totals by category and reports bad input clearly. Include tests for empty data, repeated categories, negative expenses and malformed JSON. Continue to Debugging.

Reference: Python data structures and input/output.

Course navigation

Course overview · Previous lesson · Next lesson

Section navigation