按数组中的对象分组最有效的方法是什么?

例如,给定此对象数组:

[ 
    { Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
    { Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
    { Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
    { Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
    { Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
    { Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
    { Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
    { Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
]

我正在表格中显示这些信息。我想通过不同的方法进行分组,但我想对值求和。

我将Undercore.js用于其groupby函数,这很有用,但并不能完成全部任务,因为我不希望它们“拆分”,而是“合并”,更像SQL groupby方法。

我要找的是能够合计特定值(如果需要)。

因此,如果我按阶段分组,我希望收到:

[
    { Phase: "Phase 1", Value: 50 },
    { Phase: "Phase 2", Value: 130 }
]

如果我组了阶段/步骤,我会收到:

[
    { Phase: "Phase 1", Step: "Step 1", Value: 15 },
    { Phase: "Phase 1", Step: "Step 2", Value: 35 },
    { Phase: "Phase 2", Step: "Step 1", Value: 55 },
    { Phase: "Phase 2", Step: "Step 2", Value: 75 }
]

是否有一个有用的脚本,或者我应该坚持使用Undercore.js,然后遍历生成的对象,自己计算总数?


当前回答

使用lodash库很简单

let temp = []
  _.map(yourCollectionData, (row) => {
    let index = _.findIndex(temp, { 'Phase': row.Phase })
    if (index > -1) {
      temp[index].Value += row.Value 
    } else {
      temp.push(row)
    }
  })

其他回答

解释相同的代码。喜欢它我喜欢这里

const groupBy = (array, key) => {
  return array.reduce((result, currentValue) => {
    (result[currentValue[key]] = result[currentValue[key]] || []).push(
      currentValue
    );
    console.log(result);
    return result;
  }, {});
};

USE

 let group =   groupBy(persons, 'color');

/***数组分组依据*@类别数组*@function arrayGroupBy*@return{object}{“fieldName”:〔{…}〕,…}*@静态*@作者hht*@param{string}}密钥组密钥*@param{array}数据数组**@示例01* --------------------------------------------------------------------------*从“@xx/utils”导入{arrayGroupBy};*常量数组=[* {*type:'资产',*name:'zhangsan',*年龄:33岁,* },* {*类型:'config',*name:“a”,*年龄:13岁,* },* {*类型:'run',*名称:'lisi',*年龄:“3”,* },* {*类型:'xx',*name:'timo',*年龄:'4',* },*];*arrayGroupBy(array,'type',);**结果:{*资产:[{年龄:'33',名称:'zhangsan',类型:'assets'}],*config:[{age:“13”,名称:“a”,类型:“config”}],*运行:[{age:“3”,名称:“lisi”,类型:“run”}],*xx:[{age:“4”,名称:“timo”,类型:“xx”}],* };**@example示例02 null* --------------------------------------------------------------------------*常量数组=空;*arrayGroupBy(数组,“类型”);**结果:{}**@example示例03键取消绑定* --------------------------------------------------------------------------*常量数组=[* {*type:'资产',*name:'zhangsan',*年龄:33岁,* },* {*类型:'config',*name:“a”,*年龄:13岁,* },* {*类型:'run',*名称:'lisi',*年龄:“3”,* },* {*类型:'xx',*name:'timo',*年龄:'4',* },*];*arrayGroupBy(数组,“xx”);** {}**/const arrayGroupBy=(data,key)=>{if(!data||!Array.isArray(data))返回{};常量groupObj={};data.forEach((项)=>{if(!item[key])返回;const fieldName=项[key];if(!groupObj[fieldName]){groupObj[fieldName]=[item];回来}groupObj[fieldName].push(项);});返回groupObj;};常量数组=[{type:'资产',name:'zhangsan',年龄:33岁,},{类型:'config',name:“a”,年龄:13岁,},{类型:'run',名称:'lisi',年龄:“3”,},{类型:'run',名称:“wangmazi”,年龄:“3”,},{类型:'xx',name:'timo',年龄:'4',},];console.dir(arrayGroupBy(array,'type'))<p>description('arrayGroupBy match',()=>{常量数组=[{type:'资产',name:'zhangsan',年龄:33岁,},{类型:'config',name:“a”,年龄:13岁,},{类型:'run',名称:'lisi',年龄:“3”,},{类型:'xx',name:'timo',年龄:'4',},];测试('arrayGroupBy…',()=>{常量结果={资产:[{年龄:'33',名称:'zhangsan',类型:'assets'}],config:[{age:“13”,名称:“a”,类型:“config”}],运行:[{age:“3”,名称:“lisi”,类型:“run”}],xx:[{age:“4”,名称:“timo”,类型:“xx”}],};expect(arrayGroupBy(array,'type')).toEqual(result);});test('arrayGroupBy不匹配..',()=>{//结果expect(arrayGroupBy(array,'xx')).toEqual({});});test('arrayGroupBy null',()=>{let数组=空;expect(arrayGroupBy(array,'type')).toEqual({});});test('arrayGroupBy undefined',()=>{let array=未定义;expect(arrayGroupBy(array,'type')).toEqual({});});test('arrayGroupBy空',()=>{let数组=[];expect(arrayGroupBy(array,'type')).toEqual({});});});</p>

您可以使用Alasql JavaScript库来实现:

var data = [ { Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
             { Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" }];

var res = alasql('SELECT Phase, Step, SUM(CAST([Value] AS INT)) AS [Value] \
                  FROM ? GROUP BY Phase, Step',[data]);

在jsFiddle尝试这个示例。

BTW:在大型阵列(100000条记录及以上)上,Alasql比Linq更快。参见jsPref中的测试。

评论:

这里我将Value放在方括号中,因为Value是SQL中的关键字我必须使用CAST()函数将字符串值转换为数字类型。

您可以使用本机JavaScript组数组方法(目前处于第3阶段)。

我认为,与reduce相比,或者与lodash等第三方库相比,解决方案要优雅得多。

常量产品=[{名称:“牛奶”,类型:“乳制品”},{名称:“cheese”,类型:“乳制品”},{名称:“牛肉”,类型:“肉”},{名称:“chicken”,类型:“肉”}];const productsByType=products.group((product)=>product.type);console.log(“按类型分组的产品:”,productsByType);<script src=“https://cdn.jsdelivr.net/npm/core-js-bundle@3.23.2/minified.min.js“></script>

这里有一个ES6版本,不会在空成员上中断

function groupBy (arr, key) {
  return (arr || []).reduce((acc, x = {}) => ({
    ...acc,
    [x[key]]: [...acc[x[key]] || [], x]
  }), {})
}