尝试在对象上使用 .reduce 方法

5

我有一个对象需要对其中所有嵌套的值进行求和。我的对象如下:

const json = [
{
    "other_sum": "1",
    "summary": {
        "calculations": {
            "time": 10,
            "unit": 25
        },
        "updated": "2020-06-05"
    }
},
{
    "other_sum": "1",
    "summary": {
        "calculations": {
            "time": 20,
            "unit": 5
        },
        "updated": "2020-06-05"
    }
},
{
    "other_sum": "1",
    "summary": {
        "calculations": {
            "time": 5,
            "unit": 15
        },
        "updated": "2020-06-05"
    }
},
];

我需要对所有“unit”值进行求和。

我一直在尝试使用.reduce实现这个目标,但只有当对象中有两个元素时才能正常工作,一旦我有第三个元素,就会出现错误。

我的其余代码如下:

const r = json.reduce((a, b) => a.summary.calculations.unit + b.summary.calculations.unit);
console.log(r);

目前我不太确定自己哪里出了问题。


2
你缺少初始累加器值。而且你正在访问累加器的属性,但是返回一个数字作为下一个累加器值。 - Bergi
我打赌这只是因为你没有为reduce提供起始值(在调用时它是第二个参数,在这里应该是零)。 - Touffy
2
另外,a不需要summary.calc.unit这些东西,它只是一个数字。json.reduce((a, e) => a + e.summary.calculations.unit, 0)。欢迎来到SO! - ggorlen
2
这是一个数组,不是一个对象。 - Barmar
@Barmar typeof ArrayInstance === 'object',但是 ArrayInstance instanceof Array。我知道你知道这一点,但OP可能不知道。只是一个评论来纠正你说它不是一个对象的说法,因为数组是一个对象。 - StackSlave
4个回答

4

因为这不是reduce的工作方式。从这篇文章中获取,它的工作方式如下:

Given

arrSum = function(arr){
  return arr.reduce(function(a,b){
    return a + b
  }, 0);
}

The function that we pass as the first parameter of the reduce method receives two parameters, a and b. In this code, a is our accumulator. It will accumulate our sum as our function works. b is the current value being processed.

基本上,您正在尝试访问累加器中仅为数字的“summary”。以下是可工作的片段:

json = [
{
    "other_sum": "1",
    "summary": {
        "calculations": {
            "time": 10,
            "unit": 25
        },
        "updated": "2020-06-05"
    }
},
{
    "other_sum": "1",
    "summary": {
        "calculations": {
            "time": 20,
            "unit": 5
        },
        "updated": "2020-06-05"
    }
},
{
    "other_sum": "1",
    "summary": {
        "calculations": {
            "time": 5,
            "unit": 15
        },
        "updated": "2020-06-05"
    }
},
];

const r = json.reduce((a, b) => a + b.summary.calculations.unit, 0);
console.log(r);


4

.reduce 函数传入的回调函数第一个参数是累加器,每次迭代返回的值都会成为下一次迭代的累加器。

因此,下一个项上调用的值将是 a.summary.calculations.unit + b.summary.calculations.unit,然后在下一次迭代中,你的回调函数会在这个返回的值上查找嵌套属性 a.summary.calculations.unit,但这个属性可能并不存在。

你可能想要将其改为类似以下内容:

const r = json.reduce((a, b) => a + b.summary.calculations.unit, 0);

0是初始值,用于累加器。

MDN一如既往地是一个好的参考。


挑剔一点:我建议不要在这里使用“b”--“b”是什么?对于“sort”的回调函数来说是有意义的,因为您正在比较具有相同关系的一对数字。我建议在这里使用“e”代替元素。 - ggorlen

2
reduce函数的第一个值不是一个对象,而是上一次返回的值。你可以将代码更改为以下内容。
 json.reduce((total, b) => total+ b.summary.calculations.unit, 0);

0
你可以使用我的 dig 函数:

function dig(obj, func){
  let v;
  if(obj instanceof Array){
    for(let i=0,l=obj.length; i<l; i++){
      v = obj[i]; func(v, i, obj);
      if(typeof v === 'object')dig(v, func);
    }
  }
  else{
    for(let i in obj){
      v = obj[i]; func(v, i, obj);
      if(typeof v === 'object')dig(v, func);
    }
  }
}
const json = [
  {
    "other_sum": "1",
    "summary": {
      "calculations": {
          "time": 10,
          "unit": 25
      },
      "updated": "2020-06-05"
    }
  },
  {
    "other_sum": "1",
    "summary": {
      "calculations": {
        "time": 20,
         "unit": 5
      },
      "updated": "2020-06-05"
    }
  },
  {
    "other_sum": "1",
    "summary": {
      "calculations": {
        "time": 5,
        "unit": 15
      },
      "updated": "2020-06-05"
    }
  }
];
let unitTotal = 0, timeTotal = 0;
dig(json, (v, k)=>{
  if(k === 'unit'){
    unitTotal += v;
  }
  else if(k === 'time'){
    timeTotal += v;
  }
});
console.log('unitTotal: '+unitTotal);
console.log('timeTotal: '+timeTotal);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接