使用reduce来循环JSON

时间:2017-05-03 16:54:59

标签: javascript arrays json object mapreduce

我正在使用一个reduce函数,它循环遍历我的JSON文件,并将我指定的键值汇总在一起。

这很好,直到我删除其中一个值。

我的JSON是:

[{
        "id": 100,
        "jobNumber": 1,
        "jobTasks": [{
                "id": 12,
                "cost": {
                    "amountString": 100
                }
            },
            {
                "id": 13,
                "cost": {
                    "amountString": 500
                }
            }
        ]
    },
    {
        "id": 101,
        "jobNumber": 2,
        "jobTasks": [{
                "id": 14,
                "cost": {
                    "amountString": 100
                }
            },
            {
                "id": 15
            }
        ]
    }
]

我正在使用的reduce函数是:

json.data.forEach(function(item) {
var sum = item.jobTasks.reduce(function(sum, elem) {
    return sum + elem.cost.amountString;
}, 0);
console.log('jobNumber' + item.jobNumber + ' ' + sum);
});

我正在努力实现这个目标:

jobNumber1 600
jobNumber2 100

如果我在第二个作业中添加另一个 cost.amountString ,这将正常工作,但是如上面我的JSON中所示,第一个中有两个,第二个中有一个,我收到以下错误:

TypeError: Cannot read property 'amountString' of undefined

reduce 是否需要多个或相同数量的值对才能生效?我尝试了各种for循环但没有成功。

2 个答案:

答案 0 :(得分:2)

您需要检查没有属性undefined的第二个对象的amountString值。如果对象中不存在属性amountString,则返回值0

因此,请更改return语句 return sum + elem.cost.amountString;

return sum + (elem.cost && elem.cost.amountString ? elem.cost.amountString : 0) ;

完整代码:



var json = {};
json.data = [{
        "id": 100,
        "jobNumber": 1,
        "jobTasks": [{
                "id": 12,
                "cost": {
                    "amountString": 100
                }
            },
            {
                "id": 13,
                "cost": {
                    "amountString": 500
                }
            }
        ]
    },
    {
        "id": 101,
        "jobNumber": 2,
        "jobTasks": [{
                "id": 14,
                "cost": {
                    "amountString": 100
                }
            },
            {
                "id": 15
            }
        ]
    }
]


json.data.forEach(function(item) {
var sum = item.jobTasks.reduce(function(sum, elem) {
    return sum + (elem.cost && elem.cost.amountString ? elem.cost.amountString : 0) ;
}, 0);
console.log('jobNumber' + item.jobNumber + ' ' + sum);
});




答案 1 :(得分:1)

  

TypeError:无法读取未定义

的属性'amountString'

这种情况正在发生,因为您试图取消引用未定义的值。您基本上是在撰写return sum + undefined.amountString,这与撰写return sum + null.amountString类似。你怎么解决这个问题?

除了Agalo建议的内容之外,我们还可以过滤有成本的jobTask对象:

json.data.forEach(function(item) {

    var sum = item.jobTasks
      .filter(function (j) { return j.cost; })
      .reduce(function(sum, elem) {

        return sum + elem.cost.amountString;

    }, 0);

    console.log('jobNumber' + item.jobNumber + ' ' + sum);

});

顺便说一句,请考虑使用箭头语法,因为它可以说更具可读性。

json.data.forEach((item) => {

    var sum = item.jobTasks
      .filter((j) => j.cost)
      .reduce((sum, elem) => sum + elem.cost.amountString, 0);

    console.log('jobNumber' + item.jobNumber + ' ' + sum);

});

完整的代码清单:

var json = {};
json.data = [{
    "id": 100,
    "jobNumber": 1,
    "jobTasks": [{
        "id": 12,
        "cost": {
          "amountString": 100
        }
      },
      {
        "id": 13,
        "cost": {
          "amountString": 500
        }
      }
    ]
  },
  {
    "id": 101,
    "jobNumber": 2,
    "jobTasks": [{
        "id": 14,
        "cost": {
          "amountString": 100
        }
      },
      {
        "id": 15
      }
    ]
  }
];

// with traditional functions
json.data.forEach(function(item) {

  var sum = item.jobTasks
    .filter(function(j) {
      return j.cost;
    })
    .reduce(function(sum, elem) {

      return sum + elem.cost.amountString;

    }, 0);

  console.log('jobNumber' + item.jobNumber + ' ' + sum);

});

// with arrow functions
json.data.forEach((item) => {

  var sum = item.jobTasks
    .filter((j) => j.cost)
    .reduce((sum, elem) => sum + elem.cost.amountString, 0);

  console.log('jobNumber' + item.jobNumber + ' ' + sum);

});