Skip to content

← Generators, Iterators and Streaming Data step 2 of 9

Easy Primitives

Pair Names with Scores and Reject a Length Mismatch

Your program reads two columns from a file, names and scores, and pairs them by position. If one column is longer, a row is missing somewhere. The pairing must then fail with a clear error, instead of dropping data the way plain zip does.

align(["ann", "bob"], [91.0, 88.5])
# {"ann": 91.0, "bob": 88.5}
align(["ann", "bob", "cy"], [91.0, 88.5])
# raises LengthMismatch("length mismatch: names=3, scores=2")

What to write

Fill in align(names, scores). The starter gives you LengthMismatch, a subclass of ValueError.

  • Pair each name with the score at the same position, and return a dictionary from name to score.
  • Use zip(names, scores, strict=True), and run it to the end inside a try block, for example with list(). Strict zip raises only when the loop reaches the end of the shorter column.
  • Put only the zip inside the try, so the only ValueError it can catch is the length mismatch.
  • Catch that ValueError and write raise LengthMismatch(...) from exc, so zip's error stays attached as the cause.
  • The message is exactly length mismatch: names=<n>, scores=<m>, where <n> is len(names) and <m> is len(scores). Use the same message whichever column is longer.
  • If a name appears more than once, the later score wins. dict() does this for you.

Edge cases

  • Two empty lists give {}, with no error.
  • An empty list paired with a nonempty one is a mismatch, for example length mismatch: names=0, scores=2.
  • names=["a", "a"] with scores=[1.0, 2.0] gives {"a": 2.0}.

What the driver reports

Keep solve as it is. It calls align and returns {"mapping": <your dictionary>, "error": ""}. When align raises LengthMismatch, solve returns {"mapping": {}, "error": str(exc)}, so a failed call never reports a partial mapping.