跪拜 Guibai
← All articles
JavaScript · Frontend

10 Lines of Code: The Flat-to-Tree Algorithm Every Frontend Dev Needs

By 默_笙 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

This pattern — flat storage, tree display — is the default in nearly every relational database-backed web app. Mastering the O(n) conversion means you stop writing recursive lookups that accidentally hit O(n²). It's a tiny piece of code that saves hours of debugging nested data.

Summary

When a backend runs `select * from menu`, the result is a flat array of items with a `parentId` field. But frontend components like Ant Design's Tree or Element UI's Cascader expect nested objects with a `children` array. The gap is universal in admin dashboards, address pickers, and org charts.

The solution is a two-pass algorithm. First, build an index mapping each id to its node (with an empty children array). Second, iterate again: for each node, look up its parent by parentId and push the node into that parent's children. Nodes with parentId 0 become roots. The Map version uses ES6 Map for O(1) lookups; the reduce version uses a plain object and functional style. Both run in O(n) time and O(n) space.

The key insight is that parentId is the "DNA" of the tree — it encodes the hierarchy without nesting. The algorithm simply resolves that encoding into a structure the DOM can render. A debugging bonus: `JSON.stringify(tree, null, 2)` prints the result with clean indentation.

Takeaways
Backend SQL queries return flat arrays; frontend UI components need nested trees with a children array.
The parentId field is the key: 0 means root, any other value is the id of the parent node.
The Map method uses ES6 Map to index nodes by id, then attaches each node to its parent in a second pass.
The reduce method achieves the same result with a plain object and functional reduce calls.
Both methods run in O(n) time and O(n) space — no recursion, no nested loops.
JSON.stringify(obj, null, 2) is a quick way to visualize the resulting tree in the console.
Conclusions

The algorithm is a practical example of 'space for time' — building an index upfront eliminates nested lookups.

The two-pass structure is generalizable: any problem that involves resolving references (like graph edges) can use the same pattern.

The reduce version is more elegant but less obvious to debug; the Map version is clearer for teams new to functional programming.

Most frontend developers overcomplicate this with recursion when a simple linear pass suffices.

The same pattern works for any hierarchical data: categories, comments, org charts, file systems.

Concepts & terms
Adjacency List
A database storage pattern where each row stores a parentId pointing to its parent row. Simple to query and maintain, but requires a conversion step to build a tree.
Space-for-time tradeoff
Using extra memory (like a Map index) to reduce the time complexity of an algorithm. Here, an O(n) Map lookup replaces an O(n²) nested search.
Reduce (Array.reduce)
A JavaScript array method that folds an array into a single value by applying a callback to each element. Can build objects, arrays, or any accumulator.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗