Exercise 3: Three Orders, Two Silently Dropped — Possible Solution ==================================================================== THE TEST ------------------------------ orders3 = [(200, 7, 10), (201, 7, 20), (202, 7, 30)] # customer 7 has THREE orders customers3 = [(7, 'Dana')] naive3 = hash_join_naive_overwrite(orders3, 1, customers3, 0) # built on orders correct3 = hash_join(orders3, 1, customers3, 0) RESULT ------------------------------ naive hash join (built on the 3-order side): 1 pair(s) correct hash join (built on the 3-order side): 3 pair(s) The naive version finds only 1 pair -- order 202 paired with Dana. Orders 200 and 201 are both completely missing. The correct version finds all 3, as it should. WHY TWO ROWS ARE DROPPED, NOT JUST ONE ------------------------------ hash_join_naive_overwrite()'s own build loop is: for row in build_rows: hash_table[row[build_key_idx]] = row # overwrites on every collision Processing orders3 in order: order 200 sets hash_table[7] = order 200. Order 201 OVERWRITES that same key: hash_table[7] = order 201 -- order 200 is now gone from the dict entirely, with no trace it was ever there. Order 202 overwrites it again: hash_table[7] = order 202 -- now order 201 is gone too. By the time the build loop finishes, hash_table[7] holds only order 202; orders 200 and 201 were each overwritten in turn and never recovered. WHY THE DROP COUNT SCALES WITH THE DUPLICATE COUNT, NOT A FIXED NUMBER ------------------------------ Each write to hash_table[key] is a plain dictionary assignment -- there's nothing in Python's own dict semantics that "remembers" a previous value once a new one is assigned to the same key. For a key appearing N times among the build rows, the same key gets assigned N times in a row, and only the very LAST assignment survives to be probed later. With N=2 (this chapter's own Alice example), 1 row is lost. With N=3 (this exercise), 2 rows are lost. The general pattern is N-1 rows silently lost for every key that appears N times on the build side -- the bug's own severity grows directly with how duplicated a key actually is, not some small, bounded amount of damage regardless of scale. WHY THIS MAKES THE BUG MORE DANGEROUS IN PRACTICE, NOT LESS ------------------------------ A real system where this bug went unnoticed wouldn't necessarily fail loudly or obviously -- a customer with exactly one order would never trigger it at all (no collision to overwrite), and the damage only shows up, and only grows, for customers with genuinely repeat business. The bug's own visibility is inversely related to how important the affected rows might be: the more orders a real customer has, the more of their own order history silently vanishes from any report built on this naive join. WHY THIS WORKS AS AN ANSWER ------------------------------ Extending the chapter's own two-order example to three orders, and confirming exactly two (not one, not three) rows go missing, demonstrates the bug's own severity is proportional to duplication count -- a stronger, more precise claim than simply "duplicates can be lost," and one that couldn't be confirmed from the two-order example alone, since with only two orders there's no way to distinguish "loses one row" from "loses all but one row" -- they happen to be the same outcome at N=2, and only diverge once N=3 or more is tested.