如何在JavaScript中实现对象数组多键分组求和的通用函数?
基于Lodash实现对象数组的分组求和通用函数
实现思路
完全可以通过Lodash的_.groupBy和_.sumBy结合递归逻辑实现需求,同时支持单层和多层分组场景。核心思路是逐层处理分组字段,每完成一层分组后,对剩余分组字段递归处理,直到无剩余分组字段时计算求和字段的总和。
示例数据
const data = [ { continent:'North America', country:'us', state:'ma', population: 1567986, fee: 24343 }, { continent:'North America', country:'us', state:'tx', population: 7567986, fee: 119343 }, { continent:'North America', country:'ca', state:'on', population: 467986, fee: 3343 }, { continent:'North America', country:'ca', state:'qb', population: 1268986, fee: 54248 }, { continent:'Europe', country:'ge', state:'mc', population: 4268986, fee: 97333 }, { continent:'Europe', country:'it', state:'fl', population: 978353, fee: 248 }, ];
通用函数实现(Lodash版本)
const GroupByFunction = (array, groupbyFields, sumFields) => { // 递归处理分组与求和 const groupAndSum = (items, fields) => { // 无剩余分组字段时,计算求和字段总和 if (fields.length === 0) { return sumFields.reduce((acc, field) => { acc[field] = _.sumBy(items, field); return acc; }, {}); } const currentField = fields[0]; // 按当前字段分组 const grouped = _.groupBy(items, currentField); // 对每个分组递归处理剩余字段 return _.mapValues(grouped, (groupItems) => groupAndSum(groupItems, fields.slice(1)) ); }; return groupAndSum(array, groupbyFields); };
调用示例
1. 单层分组(按continent)
const singleGroupResult = GroupByFunction(data, ['continent'], ['population', 'fee']);
输出结果:
{ 'North America': { population: 10871944, fee: 201277 }, 'Europe': { population: 5247339, fee: 97581 } }
2. 多层分组(按continent + country)
const multiGroupResult = GroupByFunction(data, ['continent', 'country'], ['population', 'fee']);
输出结果:
{ 'North America': { us: { population: 9135972, fee: 143686 }, ca: { population: 1736972, fee: 57591 } }, 'Europe': { ge: { population: 4268986, fee: 97333 }, it: { population: 978353, fee: 248 } } }
非Lodash原生实现方案
如果不想依赖第三方库,可使用原生JavaScript的Array.reduce实现:
const GroupByFunctionNative = (array, groupbyFields, sumFields) => { const groupAndSum = (items, fields) => { if (fields.length === 0) { return sumFields.reduce((acc, field) => { acc[field] = items.reduce((sum, item) => sum + item[field], 0); return acc; }, {}); } const currentField = fields[0]; // 按当前字段分组 const grouped = items.reduce((acc, item) => { const key = item[currentField]; acc[key] ??= []; acc[key].push(item); return acc; }, {}); // 递归处理剩余分组字段 return Object.fromEntries( Object.entries(grouped).map(([key, groupItems]) => [ key, groupAndSum(groupItems, fields.slice(1)) ]) ); }; return groupAndSum(array, groupbyFields); };
内容的提问来源于stack exchange,提问作者mike hennessy
相关产品推荐
相关产品推荐

