JavaScript(ES5)嵌套分组优化:如何仅调用一次groupBy函数
实现一次
_.groupBy完成嵌套分组的方案 我明白你想要的效果——只用一次Underscore的_.groupBy就能完成先按模块(moduleID/moduleTitle)、再按分类(categoryID/categoryTitle)的嵌套分组,而不是先分模块再遍历每个模块分分类对吧?没问题,咱们可以通过复合分组键+结果重组的方式实现,下面直接上代码和思路:
1. 先模拟你的数据源
假设你的原始数据是这样的对象数组:
const items = [ { moduleID: 1, moduleTitle: '前端基础', categoryID: 101, categoryTitle: 'HTML', content: 'HTML入门' }, { moduleID: 1, moduleTitle: '前端基础', categoryID: 102, categoryTitle: 'CSS', content: 'CSS布局' }, { moduleID: 2, moduleTitle: '前端框架', categoryID: 101, categoryTitle: 'Vue', content: 'Vue组件化' }, { moduleID: 2, moduleTitle: '前端框架', categoryID: 103, categoryTitle: 'React', content: 'React Hooks' }, ];
2. 一次_.groupBy+结果重组的代码
const _ = require('underscore'); // 第一步:用「模块ID-分类ID」的复合字符串作为分组键,只调用一次groupBy const groupedByCompositeKey = _.groupBy(items, item => `${item.moduleID}-${item.categoryID}`); // 第二步:将复合键的分组结果转换为你需要的嵌套结构 const nestedGroups = _.reduce(groupedByCompositeKey, (result, groupItems, compositeKey) => { // 拆分复合键,得到模块ID和分类ID const [moduleID, categoryID] = compositeKey.split('-').map(Number); // 取组内第一个元素的标题(业务上同moduleID的moduleTitle、同categoryID的categoryTitle应该一致) const { moduleTitle, categoryTitle } = groupItems[0]; // 检查当前结果中是否已有该模块的分组 let moduleGroup = _.find(result, mod => mod.moduleID === moduleID); if (!moduleGroup) { // 如果没有,创建新的模块分组并加入结果数组 moduleGroup = { moduleID, moduleTitle, categories: [] }; result.push(moduleGroup); } // 将当前分类的分组加入对应模块的categories数组 moduleGroup.categories.push({ categoryID, categoryTitle, items: groupItems }); return result; }, []);
3. 思路解释
- 复合分组键:把
moduleID和categoryID拼接成唯一字符串(比如1-101),这样一次_.groupBy就能把所有属于同一模块+同一分类的项归到一组。 - 结果重组:用
_.reduce遍历这些复合键分组,把它们重新组织成「模块包含分类」的嵌套结构——先判断模块是否已存在,不存在则创建;然后把当前分类的分组加入对应模块的分类列表。
这样就完全避免了两次遍历分组的操作,只调用了一次_.groupBy,最终得到的nestedGroups结构就是你需要的嵌套分组结果。
内容的提问来源于stack exchange,提问作者Renaud is Not Bill Gates
相关产品推荐
相关产品推荐

