Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

Python max Picks the Wrong Name: Convert Scores and Keep Each Record Together

Keep names and numeric scores paired, fix string ordering, and choose explicit tie and malformed-input rules.

By ON Lab3 min readSources checked November 10, 2026

When a row contains a name and an integer score, convert the score before comparing it. Keep the name and score in one tuple, then select the whole record with a numeric key. Text ordering can choose 8 over 15; a flattened list also loses the record boundary that makes the winning name easy to retrieve.

Start with a small failing example

A November 2026 Python Help discussion asked how to find a winning name from counted input. It also contained a compact answer that initially compared score strings, followed by a correction. That is a useful reason to test a short answer against the actual data before using it. This guide uses its own fixture and includes ties, negative values, and malformed input. It does not claim to have submitted a solution to an online judge.

rows = [["Ada", "10"], ["Ben", "8"], ["Cam", "15"]]
assert max(rows, key=lambda row: row[1])[0] == "Ben"
assert max(rows, key=lambda row: int(row[1]))[0] == "Cam"

The key function chooses what to compare. The result is still the original row, so index zero retrieves its name. Comparing a whole row instead would start with its name. Converting only some temporary variable does not change the strings already stored in other rows.

Parse counted input into typed records

This function accepts a count line followed by exactly that many records from an iterator. Each record must contain one whitespace-free name and one integer score. Extra lines after those records belong to the caller; the function deliberately leaves them untouched. A multiword-name format needs a different parsing contract.

def read_winner(lines):
    lines = iter(lines)
    try:
        count = int(next(lines))
    except StopIteration as exc:
        raise ValueError("missing count") from exc
    if count <= 0:
        raise ValueError("at least one record required")
    records = []
    for _ in range(count):
        try:
            name, raw_score = next(lines).split()
        except StopIteration as exc:
            raise ValueError("missing record") from exc
        records.append((name, int(raw_score)))
    return max(records, key=lambda record: record[1])

winner, score = read_winner("3\nAda 10\nBen 8\nCam 15\n".splitlines())
assert (winner, score) == ("Cam", 15)
print(winner)

At a console or judge that supplies this format, call read_winner(sys.stdin) after importing sys. Print the returned name if that is the requested output. Do not add prompts to a judge's output. Conversion failures and wrong field counts raise ValueError; the example keeps those failures visible instead of silently skipping rows and changing which record wins.

Make the tie rule explicit

With a numeric key, max returns the first record among equal greatest keys. If you use max(records) on (score, name) tuples, the name becomes an additional comparison field. That can silently replace an input-order tie policy with a name-order policy. Choose the rule from your real input specification rather than relying on an incidental tuple layout.

A dictionary is unnecessary for selecting one record and can overwrite duplicate names. A list of tuples preserves both duplicate names and their separate scores. Appending a name and score as separate list elements makes later iteration alternate between strings and integers; that is a representation problem rather than a reason for a nested loop.

Stream only when the records are not needed later

For large input, a running best record avoids storing every tuple. Initialize it from the first valid record or an explicit empty marker. A starting score of minus one is unsafe if all valid values can be lower. Update the name and score together whenever a strictly greater score arrives; using a greater-or-equal comparison instead changes which tied record wins.

The included regression fixture checks the displayed counterexample, first-wins ties, all-negative scores, missing rows, zero records, invalid scores, and names with extra fields. The code was run locally on Python 3.11.6, 3.13.2 and 3.14.3. It is a parser for the stated format, with no claim about every programming contest's constraints. Official input, integer conversion, maximum selection and string-splitting documentation supply the language facts.

Sources & further reading