按键值分组对象数组为嵌套父子结构的实现问题
Hey there! Let's work through this nested structure problem you're tackling. It sounds like you've started with _.map and _.groupBy but hit a snag on correctly grouping items into parent-child hierarchies based on specific key values. Let's break this down with a concrete example and a solid solution.
Example Context
First, let's define a sample flat array (similar to what you might be working with) and the target nested structure:
Initial Flat Data
const flatItems = [ { id: 1, label: 'Team Lead', parentId: null }, { id: 2, label: 'Senior Dev', parentId: 1 }, { id: 3, label: 'Junior Dev', parentId: 2 }, { id: 4, label: 'Design Lead', parentId: null }, { id: 5, label: 'UI Designer', parentId: 4 }, { id: 6, label: 'UX Designer', parentId: 4 } ];
Target Nested Structure
const nestedItems = [ { id: 1, label: 'Team Lead', parentId: null, children: [ { id: 2, label: 'Senior Dev', parentId: 1, children: [ { id: 3, label: 'Junior Dev', parentId: 2 } ] } ] }, { id: 4, label: 'Design Lead', parentId: null, children: [ { id: 5, label: 'UI Designer', parentId: 4 }, { id: 6, label: 'UX Designer', parentId: 4 } ] } ];
Step-by-Step Solution with Lodash
Here's how to fix your grouping issue and build the nested structure properly:
1. Group Items by Parent Key
First, use _.groupBy to cluster all items based on their parent identifier (in this case, parentId). This creates a lookup object where keys are parent values, and values are arrays of child items:
const groupedByParent = _.groupBy(flatItems, 'parentId');
This will produce an object like:
{ "null": [/* root items */], "1": [/* children of item 1 */], "2": [/* children of item 2 */], "4": [/* children of item 4 */] }
2. Build the Hierarchy Recursively
Next, create a recursive function that uses the grouped data to build nested children arrays for each item. This handles multiple levels of nesting (not just parent-child):
const buildNestedHierarchy = (groupedData, parentKey = null) => { // Get all items for the current parent key (fallback to empty array if none exist) const parentItems = groupedData[parentKey] || []; // Map each parent item to include its nested children return _.map(parentItems, item => ({ ...item, // Recursively build children for the current item's id children: buildNestedHierarchy(groupedData, item.id) })); }; // Generate the final nested structure const finalNestedData = buildNestedHierarchy(groupedByParent);
3. Customize for Your Specific Keys
If your grouping key isn't parentId (e.g., you're using category or parentCode), just adjust two things:
- Change the second argument in
_.groupByto your target key - Update the recursive call to use the child item's matching identifier (e.g., if grouping by
category, useitem.subcategoryas the next parent key)
Optional: Clean Up Empty Children Arrays
If you don't want empty children arrays for items with no kids, add a quick check:
return _.map(parentItems, item => { const children = buildNestedHierarchy(groupedData, item.id); return { ...item, // Only include children if there are any ...(children.length && { children }) }; });
Why This Works Better Than Basic _.map + _.groupBy
Your initial approach was on the right track, but the missing piece was recursively linking child items to their parents. By grouping first, we create a fast lookup for any parent's children, then recursion lets us traverse every level of the hierarchy seamlessly.
内容的提问来源于stack exchange,提问作者MartyMcfly

