listToTree in O(n): Why the Hash Table Beats the Brute-Force Double Loop
Admin dashboards, category pickers, and org charts all depend on this transformation. A quadratic implementation that works fine on a dozen items will silently degrade into a multi-second freeze on real datasets, and the O(n) hash-table pattern is the standard fix that every frontend developer should reach for by reflex.
Backend APIs return flat arrays because relational databases store rows, not trees. The frontend must reassemble the hierarchy using a `parentId` field. A naive double loop that searches for each node's parent hits O(n²) and freezes the UI around a thousand records. The fix is a hash table: one pass to index every node by ID, a second pass to attach each node to its parent in O(1). The result is a clean O(n) algorithm that handles tens of thousands of nodes without strain. Two JavaScript implementations — one using `Map` with `forEach`, another using a plain object with `reduce` — achieve the same performance. The `Map` version avoids prototype-pollution edge cases and is the safer production default. Common pitfalls include missing root-node identifiers, shared object references between the map and the output tree, and broken root detection when an `id: 0` node exists.
The two-pass approach is more robust than a single-pass recursive build because it decouples node registration from parent-child attachment, making it immune to ordering issues where a child appears before its parent in the flat array.
The `Map` vs. plain-object debate in this context is less about performance and more about correctness under adversarial keys; `Map` eliminates an entire class of bugs that most developers never think about until a `__proto__` or `constructor` key appears in production data.
The article's framing of the brute-force method as 'don't learn it, just know how bad it is' is practical pedagogy: it acknowledges the intuitive solution while immediately steering developers toward the production-grade alternative.