GroupBy将对象数组转换为新数组并求和

时间:2020-06-30 19:56:55

标签: javascript json

我在下面有一个这样的数组,我正在尝试通过将两个值分组来将对象分离到新数组中。

数组:

[
 {
    "year": "202003",
    "cost": 11194.55,
    "type": "A"
  },
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202004",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202003",
    "cost": 4674.59,
    "type": "D"
  }
]

结果应该是这样;

输出

[
 [
  {
   "year": "202003",
   "cost": 11194.55,
   "type": "A"
  }
 ],
 [ 
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  }
 ],
 [
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  }
 ],
 [
  {
    "year": "202003",
    "cost": 1494.24,     // sum of the COST value when year and type same.
    "type": "D"
  },
  {
     "year": "202004",
     "cost": 4674.59,
     "type": "D"
  }
 ]
];

我尝试过的事情

<script src="//cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>
let aggregatedObject = Enumerable.From(data)
            .GroupBy("$.type", "$.year",
                function (key, g) {
                    return {
                        label: key,
                        value: g.Sum("$.cost"),
                    }
                })
            .ToArray();

如何将此类数据分组?是否有任何库或函数可以执行此操作?我还没找到 任何帮助将不胜感激!

4 个答案:

答案 0 :(得分:1)

您可以使用Array.reduce来累积费用。

const data = [
  {
    year: '202003',
    cost: 11194.55,
    type: 'A',
  },
  {
    year: '202003',
    cost: 60.2,
    type: 'B',
  },
  {
    year: '202003',
    cost: 747.12,
    type: 'C',
  },
  {
    year: '202003',
    cost: 747.12,
    type: 'D',
  },
  {
    year: '202004',
    cost: 747.12,
    type: 'D',
  },
  {
    year: '202003',
    cost: 4674.59,
    type: 'D',
  },
];

const final = data.reduce((result, current) => {
  const key = `${current.year}-${current.type}`;
  result[key] = result[key] || {...current, cost: 0};
  result[key].cost += current.cost;
  return result;
}, {});

console.log(Object.values(final).map(item => ([item])));

答案 1 :(得分:1)

您可以尝试使用array.reduce而不是linq.js,如果有匹配的yeartype,则每次回调执行都会累积数据,或者将对象的副本添加到从函数返回的数组:

let data = [
 {
    "year": "202003",
    "cost": 11194.55,
    "type": "A"
  },
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202004",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202003",
    "cost": 4674.59,
    "type": "D"
  }
];

let aggregatedObject = data.reduce((acc,cur) => {
   let prev = acc.find(x => x.year === cur.year && x.type === cur.type);
   if(!prev){
       acc.push([{...cur}]);
   } else {
       prev.cost += cur.cost;
   }
   return acc;
}, []);

console.log(aggregatedObject);

答案 2 :(得分:1)

查看您的初始数组和想要获取的输出,以下是根据您的问题得出的结构完全相同的示例-对象数组的数组


使用findfor of loop的一种方式:

let arr = [
 {
    "year": "202003",
    "cost": 11194.55,
    "type": "A"
  },
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202004",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202003",
    "cost": 4674.59,
    "type": "D"
  }
]

let sortedArray = []
for (let [index, el] of arr.entries()) {
  if(sortedArray.find(elInner => (elInner[0].type === el.type && elInner[0].year !== el.year))) {
    sortedArray.find(elInner => elInner[0].type === el.type).push(arr[index])
  }else if (sortedArray.find(elInner => (elInner[0].type === el.type && elInner[0].year == el.year))) {
    sortedArray.find(elInner => (elInner[0].type === el.type && elInner[0].year == el.year))[0].cost += arr[index].cost
  }else {
    sortedArray.push([el])
  }
}
console.log(sortedArray)


和使用reducemap

的另一种“更清洁”的方式

let arr = [
 {
    "year": "202003",
    "cost": 11194.55,
    "type": "A"
  },
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202004",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202003",
    "cost": 4674.59,
    "type": "D"
  }
]

let sortedArray = arr.reduce((acc, obj) => {
  const key = obj.type, year = obj.year
  !!acc[key] 
  ? (!!acc[key][year] ? acc[key][year].cost += obj.cost : acc[key][year] = obj) 
  : (acc[key] = [], acc[key][year] = obj)
    return acc
}, [])

sortedArray = Object.values(sortedArray).map((val) => Object.values(val))

console.log(sortedArray)

答案 3 :(得分:1)

您可以使用带有linq作为参数的组合键和组合对象以获取总和。

var data = [{ year: "202003", cost: 11194.55, type: "A" }, { year: "202003", cost: 60.2, type: "B" }, { year: "202003", cost: 747.12, type: "C" }, { year: "202003", cost: 747.12, type: "D" }, { year: "202004", cost: 747.12, type: "D" }, { year: "202003", cost: 4674.59, type: "D" }],
    result = Enumerable
        .From(data)
        .GroupBy(
            null,
            null,
            "{ year: $.year, cost: $$.Sum('$.cost'), type: $.type }",
            "$.year + '|' + $.type"
        )
        .ToArray();

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>