Summarizing Your Data

Comparing Reasonable Approaches


Learning Objectives

  • You can recognise when a problem has more than one reasonable solution.
  • You can elicit an alternative approach from an AI assistant and compare it to your own.
  • You can evaluate two approaches across four axes — correctness, clarity, edge-case behaviour, and how each would change if requirements changed.

This is the AI-collaboration chapter for the part. The previous parts have focused on reading, verifying, specifying, and detecting plausible-but-wrong code. In this part, the focus is on comparing approaches — to know that there is usually more than one reasonable answer, and to choose between them deliberately.

A Set of Real Choices

The summaries in this part have been chosen partly because they each present a real comparison. Take a moment to look at some of the choices side by side:

QuestionFirst approachAlternative
Extract minutes columnList-building loopList comprehension
Long sessionsFiltering loopFiltered comprehension
Top three sessionsSort and sliceKeep the explicit version (or repeated max-find)
Date conversionParse inside each helperValidate in the loader, assume valid downstream

None of the entries are wrong. They are all defensible choices, and each has small consequences that matter only sometimes. The skill is producing the comparison and choosing on real grounds, rather than accepting whichever you see first.

Four Axes for Comparison

When two versions of a function both work, the useful comparison is not “which is shorter?” It is along four axes that matter for code you have to live with.

Correctness. Do the alternatives produce the same answer? They should — but two implementations that pass the same casual tests can disagree on inputs no one thought to check. Run both versions against the edge-case tests from earlier in this part and see whether they actually agree.

Clarity. Which version is easier to read for the next person? “Easier to read” depends on the audience; often, it is the version of yourself who comes back to the code in three months. That reader will appreciate code that states what it is doing in a way that does not require remembering tricks.

Edge-case behaviour. What does each version do on the empty input, on tied values, on inputs the function was not designed for? Two implementations can agree on regular data and disagree on the boundary. If the alternatives differ on the boundary, the one that matches the spec wins.

Changeability. Code is never finished. Some implementations are easier to extend than others. If the requirements grew — “totals for every subject, not just math”, “the top five days, not just the top three” — which version handles the change with a small edit, and which needs a restructure?

There are more than just these four; performance matters at large scales, memory matters in tight environments, and so on. In an introductory programming course, where the projects and data quantities are small and where applications are used by a single user, the four are usually enough.

Python Comes with Sum and Max

So far in the course, we’ve explicitly used an accumulator to count totals and a variable to keep track of “best so far” values. Now that you know the pattern, you can use Python’s built-in functions that do the same thing: sum and max.

For example, when counting the total minutes, you can write an explicit loop:

def total_minutes_in_sessions(sessions):
total = 0
for subject, minutes, day in sessions:
total += minutes
return total

Or you can extract the minutes column with a list comprehension and use sum:

def total_minutes_in_sessions(sessions):
minutes_list = [minutes for subject, minutes, day in sessions]
return sum(minutes_list)

The same goes for finding the maximum — you can write a “best so far” loop:

def longest_session(sessions):
if len(sessions) == 0:
return None
best = sessions[0]
for session in sessions:
if session[1] > best[1]:
best = session
return best

Or, you can use max with a key function:

def by_minutes(session):
return session[1]
def longest_session(sessions):
if len(sessions) == 0:
return None
return max(sessions, key=by_minutes)

Both options are valid. The internal logic is the same, but the second version uses built-in functions that come with Python. The choice between them depends on the four axes of comparison: correctness, clarity, edge-case behaviour, and changeability.

A Worked Comparison: Heaviest Day

Let’s look at a function for calculating the heaviest day. The “best so far” loop is one way to do it; using max with a key function is another. Both use the totals_by_day function from Summaries by Day to get the daily totals first, and then find the maximum.

def heaviest_day_loop(sessions):
totals = totals_by_day(sessions)
if len(totals) == 0:
return None
best = totals[0]
for row in totals[1:]:
if row[1] > best[1]:
best = row
return best

An alternative, using Python’s built-in max with a key function:

def by_total(row):
return row[1]
def heaviest_day_max(sessions):
totals = totals_by_day(sessions)
if len(totals) == 0:
return None
return max(totals, key=by_total)

Both functions do the same job, and to the function that calls them, they look practically identical. We can compare them on the four axes:

Correctness. On the regular fixture from earlier chapters — five sessions across three distinct days, with one heaviest — both produce ["2026-05-10", 135]. On the empty case, both return None. So for non-tied inputs, they are equivalent.

The tie test is where they diverge. Two days tied at sixty minutes:

tied = [
["math", 60, "2026-05-10"],
["math", 60, "2026-05-11"],
]
heaviest_day_loop(tied) # ['2026-05-10', 60] -- earliest tied day
heaviest_day_max(tied) # ['2026-05-10', 60] -- earliest tied day too

Both honour the “earliest tied day” rule, for slightly different reasons. The heaviest_day_loop version uses > (not >=), so the later row does not displace the earlier one. Internally, heaviest_day_max settles ties on input position, and the input from totals_by_day is already in date order, so the first appearance (which is the earliest date) wins.

Clarity. Both are short. The version with max is shorter and reads more directly: “the row whose total is largest”. The version with the loop is more explicit about what is being tracked and how ties are handled. For a reader who already understands max with a key, the version with max is faster to read. For a reader who is still building intuition, the version with the loop makes the algorithm visible.

Edge-case behaviour. Already covered: empty is the same, tied is the same. Both pass the same boundary tests.

Changeability. If you needed the top three heaviest days instead of just the heaviest, both would have to be substantially restructured. For the current requirement, this is irrelevant; for foreseeable changes, neither version has a clear advantage, but both require rewrites.

So which one wins? Neither. The version with the loop is a little more obviously correct to a reader who is still learning. The version with max is more concise once you know max with a key. Either is fine — and noticing the trade-off is what made the choice visible.

The next essay asks you to compare two reasonable summary implementations using the same four axes.

Compare two summary implementations

0 / 10 points

Compare the two implementations below. They both try to return the route row with the largest total minutes, or None for an empty list.

def busiest_route_loop(route_totals):
if len(route_totals) == 0:
return None
best = route_totals[0]
for row in route_totals[1:]:
if row[1] > best[1]:
best = row
return best
def by_minutes(row):
return row[1]
def busiest_route_key(route_totals):
if len(route_totals) == 0:
return None
return max(route_totals, key=by_minutes)

In 5-8 sentences, compare the implementations across correctness, clarity, edge cases, and how easy they would be to change later.

Shorter Code Does Not Mean Better Code

The “shorter version” is often presented (by AI assistants, by tutorials, etc.) as the better version. A few specific cases where that is wrong:

When the shorter version silently changes the boundary behaviour. max(values) raises ValueError on an empty list; the explicit “best so far” version returns None if you wrote it that way. The shorter version is not equivalent — it is a different function that happens to agree on most inputs.

When the reader does not know the idiom. A list comprehension is unfamiliar to a true beginner. If your code is going to be read by people just learning Python, an explicit loop is kinder. This course keeps writing both forms partly for this reason.

When the compression hides a design decision. Idiomatic code is sometimes idiomatic because everyone agrees on what should happen; other times it is idiomatic because the original author made a choice and the readers stopped noticing. The longer version often makes the choice visible; the idiomatic version often hides it.

When you would have to undo it next week. If the requirements are likely to grow, writing the maximally-compact version of the current requirement can mean rewriting it the moment the next requirement comes in. A loop you would have to keep is sometimes a better starting point than a comprehension you will throw away.

These are not arguments against idioms generally. They are arguments against automatically preferring the shorter version. The honest position: each version has costs and benefits, and the choice belongs to whoever has to live with the code.

Some choices are not mainly about shorter or longer code, but about the rule the program promises to users. Compare two current-streak rules next.

Compare current-streak rules

0 / 10 points

Compare two possible rules for a current streak:

  • Strict reset: the current streak is positive only when the latest logged day is today.
  • Grace rule: the current streak is positive when the latest logged day is today or yesterday.

In 5-8 sentences, compare the rules across correctness for the chosen specification, user expectations, edge cases, and testing. Mention what each rule returns when today is June 10 and the latest logged day is June 9.

The Skill, in Practice

When an AI gives you code, the comparing-approaches skill is small and specific. You do these things:

  1. Read the version it gave you. — you cannot compare what you do not understand.
  2. Verify it. — on the inputs you care about, including the boundary.
  3. Ask for an alternative. “Can you write this a different way?” or “What is another reasonable approach to this?” An assistant may produce a different approach; your job is to check whether it is meaningfully different and still correct.
  4. Compare on the four axes. Correctness on every input you care about. Clarity for the reader you have in mind. Edge-case behaviour against the spec. Changeability against the requirements you can foresee.
  5. Choose, and document the choice. A short comment in your code — “using the explicit loop because the empty-list handling is more visible than max(...) would be” — captures the decision in a way that helps the next reader and helps future-you remember.

Having two or more options on the table makes the choice visible. If you only ever see one approach, you cannot reason about the trade-offs of using a different one. The skill produces the comparison; the choice is yours.

This prompt exercise practises asking for an alternative implementation and tests, while keeping the required behaviour explicit.

Prompt an alternative busiest-day helper

0 / 10 points

Write a prompt that asks a large language model to create Python code only.

The generated code must define a function named busiest_day(day_totals) with this exact behavior:

  • day_totals is a list of rows where each row is [date_string, total_minutes],
  • return the row with the largest total_minutes,
  • return None when day_totals is empty,
  • if two rows have the same largest total, return the one that appears earlier in the list,
  • do not change the original list,
  • do not call input(...),
  • and do not print anything.

Include the following example in your prompt:

busiest_day([
["2026-05-01", 40],
["2026-05-02", 70],
["2026-05-03", 70],
])

The required return value is:

["2026-05-02", 70]

Ask for Python code only. Also ask the model to include a few small assert examples after the function, but the function itself must work when imported by tests.

Where You Are in the Nine-Skill Arc

Five skills are in place. Each new one builds on the previous, not replaces:

PartAI skillWhat it gives you
1Reading code you didn’t writeKnowing what a piece of code does
2Verifying behavior and finding edge casesKnowing whether what it does is right
3Specifying what you wantKnowing what to ask for in the first place
4Detecting plausible-but-wrong codeKnowing when “it runs” is not “it works”
5Comparing approachesKnowing how to choose between several right answers
6Critiquing data designs
7Working with AI on libraries you’re learning
8Critiquing AI-suggested visualizations
9Iterating with AI on a project

Check Your Understanding

  1. Explain what the max function does when given a key argument. What does the key argument do and how does it affect the result of max?
  2. Two versions of heaviest_day were compared. They produced the same answer on the tie test — but for different reasons. What were the two reasons?
  3. What are the four axes for comparing approaches that this chapter lists?
  4. The chapter recommends asking the AI “can you write this a different way?” after you have already written your own version. What is the value of doing it this way around?
  5. A colleague says: “the comprehension version is better, it’s shorter.” What is wrong with that argument?

AI Study Aid

Create a chapter diagram

We're looking into to what extent AI-generated diagrams could help with studying.

Use this study aid to generate an AI-generated visual summary of the material you just studied. Each diagram style emphasizes the content in a different way, so you can choose the focus that feels most useful.

Using the diagram generator is voluntary and does not affect your course progress. We encourage you to try it out and see if it helps, but it's totally up to you! Your answers help us understand how to make better study aids in the future.

Diagrams tried: 0