Card 03/ 08

CodeDifficulty: Intermediate3 min

Tracing the Finished Code on the Hand-Worked Examples

Run the listing by hand on the examples from step two, edge cases included, before trusting it with anything larger.

Tracing is the sixth step: following each variable through the code, line by line, on an input small enough to hold in your head, and checking what the code produces against the answer worked by hand. This card traces a function that finds the first ticket scanned twice at a gate, on the scans 7 3 9 3, then runs it in Python, Java and TypeScript on that input and four edge cases: no scans, one scan, every scan the same, and no repeat. The hand-worked examples become the tests, which is why they are written down before any code.

The trace follows the set of tickets seen after each scan. An instrumented copy of the Python function printed it, showing the set in sorted order.

text
scan 1: 7 is not in the set (empty), add it
scan 2: 3 is not in the set 7, add it
scan 3: 9 is not in the set 3 7, add it
scan 4: 3 is in the set 3 7 9, return 3
The set after each scan of 7 3 9 3

Each edge case guards one line. No scans checks that the loop can run zero times and still return. One scan checks that a ticket is never compared with itself. Every scan the same checks that the repeat is caught at the second scan rather than the last. No repeat checks the return after the loop. Each listing prints one line per input; the highlighted lines are the membership test and the insertion, whose order is what keeps a ticket from matching itself.

The first repeated ticket on five inputs, in each language

first_repeat.pypy
def first_repeat(scans: list[int]) -> int | None:
    seen: set[int] = set()
    for ticket in scans:
        if ticket in seen:
            return ticket
        seen.add(ticket)
    return None


examples = {
    "ordinary": [7, 3, 9, 3],
    "no scans": [],
    "one scan": [5],
    "all the same": [5, 5, 5],
    "no repeat": [7, 3, 9],
}
for name, scans in examples.items():
    result = first_repeat(scans)
    print(f"{name}: {'none' if result is None else result}")
OutputRan with python:3.14.8-slim-trixie (Python 3.14.8)
ordinary: 3
no scans: none
one scan: none
all the same: 5
no repeat: none
FirstRepeat.javajava
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class FirstRepeat {
    static Integer firstRepeat(int[] scans) {
        Set<Integer> seen = new HashSet<>();
        for (int ticket : scans) {
            if (seen.contains(ticket)) {
                return ticket;
            }
            seen.add(ticket);
        }
        return null;
    }

    public static void main(String[] args) {
        Map<String, int[]> examples = new LinkedHashMap<>();
        examples.put("ordinary", new int[] {7, 3, 9, 3});
        examples.put("no scans", new int[] {});
        examples.put("one scan", new int[] {5});
        examples.put("all the same", new int[] {5, 5, 5});
        examples.put("no repeat", new int[] {7, 3, 9});
        for (Map.Entry<String, int[]> example : examples.entrySet()) {
            Integer result = firstRepeat(example.getValue());
            System.out.println(example.getKey() + ": " + (result == null ? "none" : result));
        }
    }
}
OutputRan with eclipse-temurin:25.0.4.1_1-jdk-noble (Java 25.0.4.1)
ordinary: 3
no scans: none
one scan: none
all the same: 5
no repeat: none
first_repeat.tsts
function firstRepeat(scans: number[]): number | null {
  const seen = new Set<number>();
  for (const ticket of scans) {
    if (seen.has(ticket)) {
      return ticket;
    }
    seen.add(ticket);
  }
  return null;
}

const examples: [string, number[]][] = [
  ["ordinary", [7, 3, 9, 3]],
  ["no scans", []],
  ["one scan", [5]],
  ["all the same", [5, 5, 5]],
  ["no repeat", [7, 3, 9]],
];
for (const [name, scans] of examples) {
  const result = firstRepeat(scans);
  console.log(`${name}: ${result === null ? "none" : result}`);
}
OutputRan with node:24.22.0-trixie-slim (Node 24.22.0), TypeScript 5.9.3
ordinary: 3
no scans: none
one scan: none
all the same: 5
no repeat: none

All three print the same five lines, and each matches the answer worked by hand. Java returns Integer rather than int so that null can mean no repeat, and TypeScript returns number | null for the same reason. A return of −1 would also work here, but only because the clarify step established that tickets are positive; on input that may hold −1, the sentinel would be indistinguishable from a real answer.