跪拜 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 ↗