LambdaLabTM
Computer Science · Class 11 · Tuples Revisited
TuplesPrograms⏱️ 14 min read

Smallest, Largest & Mean

Three of the programs the syllabus names outright, and they are one program each. Python has max(), min() and sum() and will do all three in a line — but the exam asks for the loop, and the loop is the version that survives when the question gets fussier, as it does at the end of this page.

1Program 1 — the largest, without max()

📋 The problem

Find the highest mark in a tuple, without using max().

largest.py
# the highest mark, by keeping a champion

marks = (56, 91, 43, 78, 65)
largest = marks[0]

for m in marks:
    if m > largest:
        largest = m

print('Largest:', largest)
Output
Largest: 91
largest = marks[0]

The best seen so far, and it starts as a real member of the tuple. Made before the loop, so it survives every round.

if m > largest:

One question per item: is this one better than the best so far? Most rounds the answer is no and nothing happens, which is fine.

largest = m

The new champion. Note it stores the mark, not the position — reporting where it was is a different program, further down.

Key Takeaway
The champion starts at marks[0], never at 0. Zero looks harmless because marks cannot be negative — and then the same code is used on temperatures:
bad_start.py
# the same program with largest = 0, on winter temperatures

temps = (-4, -11, -7, -2)
largest = 0

for t in temps:
    if t > largest:
        largest = t

print('Largest (wrong):', largest)
Output
Largest (wrong): 0

It reports 0, which is not in the tuple at all. Nothing crashed and nothing looked odd. marks[0] can never do this, because it really is one of the candidates.

2Program 2 — the largest and the smallest together

📋 The problem

Find the highest and the lowest mark in one pass.

largest_smallest.py
# both champions, one loop

marks = (56, 91, 43, 78, 65)
largest = marks[0]
smallest = marks[0]

for m in marks:
    if m > largest:
        largest = m

    if m < smallest:
        smallest = m

print('Largest: ', largest)
print('Smallest:', smallest)
Output
Largest:  91
Smallest: 43
Watch Out
Two separate ifs — not if…elif. Both questions have to be asked of every mark. With an elif, a mark that beat the largest would never be tested against the smallest. On this tuple it happens not to matter; on a tuple whose first item is the smallest it does.

3Program 3 — the mean, without sum()

📋 The problem

Work out the average of a tuple of marks, without sum().

mean.py
# the total, then the mean

marks = (56, 91, 43, 78, 65)
total = 0

for m in marks:
    total = total + m

print('Total:', total)
print('Mean: ', total / len(marks))
Output
Total: 333
Mean:  66.6

Divided by len(marks) and not by 5, so adding a sixth mark needs no other change. And the division is /, not //: a mean of 66.6 is the answer, and // would report 66.

mean_round.py
# a mean is usually printed to two decimals

marks = (72, 65, 88, 91, 54, 77)
total = 0

for m in marks:
    total = total + m

print('Mean:', round(total / len(marks), 2))
Output
Mean: 74.5

4The same three, in one line each

builtin.py
# what you would actually write outside an exam

marks = (56, 91, 43, 78, 65)

print('Largest: ', max(marks))
print('Smallest:', min(marks))
print('Total:   ', sum(marks))
print('Mean:    ', sum(marks) / len(marks))
Output
Largest:  91
Smallest: 43
Total:    333
Mean:     66.6
Tip
Both versions are worth knowing, for different reasons. The built-ins are what real code uses and what a question means by “find the largest” when it does not say otherwise. The loop is what a question means by “without using max()” — and it is the only one of the two that can be bent into a new shape, which the next two programs need.
Watch Out
max() of an empty tuple is an error, not 0. ValueError: max() iterable argument is empty. The loop version fails earlier and more obviously — marks[0] on an empty tuple raises IndexError — but either way, a program that might be handed nothing has to check len() first.

5Program 4 — where the largest is

📋 The problem

Report the highest mark and the position it is at.

This is the first question max() cannot answer, and it is why the index form of the loop exists:

where_largest.py
# the largest, and which student it belongs to

marks = (56, 91, 43, 78, 65)
largest = marks[0]
where = 0

for i in range(len(marks)):
    if marks[i] > largest:
        largest = marks[i]
        where = i

print('Largest:', largest, 'at position', where)
print('That is student number', where + 1)
Output
Largest: 91 at position 1
That is student number 2

Two variables move together inside the same if, exactly as the name and the mark did in the topper program. Update one without the other and the program reports a real mark at the wrong position.

6Program 5 — the second largest

📋 The problem

Find the second highest mark in a tuple.

The tempting answer — keep two champions and shuffle them along — is fiddly to get right. Two passes is easier to read and easier to trust: find the largest, then find the largest of everything that is not it.

second_largest.py
# the second largest, in two passes

marks = (56, 91, 43, 78, 65)

largest = max(marks)
second = min(marks)

for m in marks:
    if m > second and m != largest:
        second = m

print('Largest:       ', largest)
print('Second largest:', second)
Output
Largest:        91
Second largest: 78
second = min(marks)

The second champion starts at the smallest mark — a real member again, and one that every other candidate beats or ties.

if m > second and m != largest:

Two conditions: better than the best runner-up so far, and not the winner itself. Drop the second half and the answer comes back equal to largest.

Watch Out
If every mark is the same, there is no second largest. On (5, 5, 5) this program prints 5 twice, because every item equals largest and nothing ever replaces second. That is not a bug to patch quietly — it is a question the data cannot answer, and a real program would say so.
second_largest.py

7Recap

A champion starts inside the tuple

marks[0] is always safe. 0 or 100 can win, and then the answer is a number that was never in the data.

Collector above, test inside, print after

total = 0 and largest = marks[0] are both made before the loop. Inside it they only ever change.

Two ifs, not if…elif

When two questions must both be asked of every item, an elif silently skips one of them.

max() answers what, never where

The moment the position is part of the answer, you are back to for i in range(len(marks)).

✍️ Now write these yourself
  1. 1

    Find the longest name in a tuple of names, without max().

    Hint · The champion program with len(n) > len(longest), starting at names[0].

  2. 2

    Print how far the highest mark is above the mean.

    Hint · Two passes: work out the mean, then max(marks) - mean. Round it before printing.

  3. 3

    Count how many marks are above the mean.

    Hint · Also two passes — the mean does not exist until the first one has finished, so nothing can be compared with it during that pass.

  4. 4

    Report the smallest number and the position it sits at, in one loop.

    Hint · Program 4 with <. Both smallest and where update inside the same if.

Quick Check

Why must largest start at marks[0] rather than at 0?

Quick Check

Which of these can max() not do?

Quick Check

In the second-largest program, why is `and m != largest` needed?