Javascript 按多个数组的对象类别查找深度嵌套数组数据的总和

Javascript 按多个数组的对象类别查找深度嵌套数组数据的总和,javascript,arrays,sum,Javascript,Arrays,Sum,我有一个函数,它返回两个单独的数组,其中包含两个数组 [Array(3), Array(3)] [Array(3), Array(3)] 这些嵌套数组每个包含6个对象 {value: "10.50", category: "a"}, {value: "55.50", category: "a"} {value: "10.50", category: "b"}, {val

我有一个函数,它返回两个单独的数组,其中包含两个数组

[Array(3), Array(3)]

[Array(3), Array(3)]
这些嵌套数组每个包含6个对象

{value: "10.50", category: "a"}, 
{value: "55.50", category: "a"}
{value: "10.50", category: "b"}, 
{value: "35.50", category: "b"},
{value: "15.50", category: "c"},
{value: "45.50", category: "c"}
我试图遍历每个主要的2个数组,并按类别返回嵌套数组的合计值,如下所示:记住当前值是一个字符串

[
 [
  {value: "66.00", category: "a"},
  {value: "46.00", category: "b"},
  {value: "61.00", category: "c"},
 ]
]
我尝试了下面的方法,但我似乎无法正确地理解,我已经看过很多这样的线程,我知道有很多类似的线程,但到目前为止没有任何东西对我有效。蒂亚

我拙劣的尝试

  const x = array.forEach((data) => {
    data.reduce(function (
      acc: any[],
      val: { category: string; value: string }
    ) {
      const o = acc
        .filter(function (obj) {
          return obj.category === val.category;
        })
        .pop() || { category: val.category, value: 0 };

      o.value += parseFloat(String(val.value));
      acc.push(o);
      return acc;
    },
    []);
  });

听起来您只需要将对象分组到一个按
类别
索引的对象中,将值相加,确保将字符串强制为数字,然后将其返回到一个对象数组中:

const outerar=[
[
{值:“10.50”,类别:“a”},
{值:“55.50”,类别:“a”},
{值:“10.50”,类别:“b”},
{值:“35.50”,类别:“b”},
{值:“15.50”,类别:“c”},
{值:“45.50”,类别:“c”}
],
//等
];
const final=outerArr.map((subar)=>{
const grouped={};
for(subar的常量{值,类别}){
分组[类别]=(分组[类别]| | 0)+数字(值);
}
返回Object.entries(grouped.map)([category,value])=>({value:value.toFixed(2),category}));
});

控制台日志(最终)
听起来您只需要将对象分组到由
类别索引的对象中,将值相加,确保将字符串强制为数字,然后将其转换回对象数组:

const outerar=[
[
{值:“10.50”,类别:“a”},
{值:“55.50”,类别:“a”},
{值:“10.50”,类别:“b”},
{值:“35.50”,类别:“b”},
{值:“15.50”,类别:“c”},
{值:“45.50”,类别:“c”}
],
//等
];
const final=outerArr.map((subar)=>{
const grouped={};
for(subar的常量{值,类别}){
分组[类别]=(分组[类别]| | 0)+数字(值);
}
返回Object.entries(grouped.map)([category,value])=>({value:value.toFixed(2),category}));
});

控制台日志(最终)最终值为字符串格式,但您可以根据需要进行更改。 单个阵列的示例:

Object.entries(
  arr.reduce((acc,curr)=>{
    acc[curr.category] = (acc[curr.category] || 0.0) + parseFloat(curr.value)
    return acc;
  },{})
)
.map(([a,b])=>({category:a,value:b.toFixed(2).toString()}));

最终值为字符串格式,但您可以根据需要进行更改。 单个阵列的示例:

Object.entries(
  arr.reduce((acc,curr)=>{
    acc[curr.category] = (acc[curr.category] || 0.0) + parseFloat(curr.value)
    return acc;
  },{})
)
.map(([a,b])=>({category:a,value:b.toFixed(2).toString()}));

对于你的问题,还有其他几个好的答案,尽管我认为这个答案更短、更快、更容易理解。(查看我的解决方案底部的工作示例)。我们可以使用一些简单的数组和对象方法来实现这一点

1.整合数据 首先,我们将把每个嵌套的对象数组合并到单个对象中,以类别(我们的唯一值)作为键及其值。我们可以使用array
reduce()
方法来实现这一点。这里我们将使用
{}
作为累加器的初始值,然后通过设置累加器对象的属性将其推送到累加器对象。在迭代过程中,我们将把每个值添加到关联的category属性中。如果尚未在累加器对象上设置属性,则可能会导致错误

解决此问题的一种方法是使用三元值检查属性是否存在,然后如果属性不存在,则设置属性,如果存在,则添加值,如下所示:

//a是累加器,c是类别名称,v是值
a[c]?a[c]+=parseFloat(v):a[c]=parseFloat(v)/->{a:66,b:46,c:61}
一种更简单的方法是使用空合并。null合并将检查该值是否为null或未定义,如果是,则使用
0
作为当前值。在这个方法中,我们总是设置属性,只需将其自身(或
0
)添加到正在计算的当前值中即可覆盖它,如下所示:

a[c]=(a[c]?0)+parseFloat(v)/->{a:66,b:46,c:61}
在我的reduce方法中设置参数名时,我还选择使用对象重构,以便于我访问所有三个变量。不过,这不是必需的,因此以下两种方法的工作原理相同。使用对象解构还允许我们重命名解构的参数,以便于使用(
c,v
,而不是
category,value
)。要了解有关分解和重命名参数的更多信息,请查看Wes Bos的帖子

//不进行对象分解
arr.reduce((a,o)=>(a[o.category]=(a[o.category]?-0)+parseFloat(o.value),a),{});
//使用对象分解
arr.reduce((a,{value:v,category:c})=>(a[c]=(a[c]??0)+parseFloat(v,a),{});
2.将合并对象扩展为对象数组 一旦我们为每个对象数组设置了简化对象(例如,
{a:66,b:46,c:61}
),我们的下一个任务就是将其转换回我们开始使用但现在已合并的对象系列格式。为此,我们首先使用
object.entries()
方法将键值对的新对象转换为嵌套数组数组。这将允许我们将数组重新映射为一个对象数组,在此过程中,我们将重写所需的键名,并将编号的值转换回固定十进制计数为2的字符串

在前面的步骤中,我们使用对象的属性名来分解对象。这一次,因为
Object.entries()
以数组的形式返回数据,所以我们将使用数组分解。这类似于对象分解,只是在重构数组时需要使用括号。请记住始终将解构参数括在括号中,否则会出现错误:

//obj={a:66,b:46,c:61};
Object.entries(obj.map)([c,v]=>({value:v.toFixed(2),category:c}))
// !!! 未捕获的语法错误:格式错误的箭头函数参数列表
Object.entries(obj.map)([c,v])=>