【问题标题】:Confused, Looping over nested Object and doing specific calculations困惑,循环嵌套对象并进行特定计算
【发布时间】:2016-11-11 18:49:10
【问题描述】:

我被困住了!我有以下代码:

const hours = [
    {
        "workHour" : "8",
        "Item name 1" : 120,
        "Item name 2" : 149,
        "Item name 3" : 137
    },
    {
        "workHour" : "9",
        "Item name 1" : 134,
        "Item name 2" : 119,
        "Item name 3" : 144
    },
    {
        "workHour" : "10",
        "Item name 1" : 60,
        "Item name 2" : 86,
        "Item name 3" : 83
    },
];

const records = [
   { date: new Date(), statistics: hours },
   { date: new Date(), statistics: hours },
   { date: new Date(), statistics: hours },
];

const result = {};
result.chart = [];

records.forEach((record) => {
   const items = [];
   record.statistics.forEach((hour) => {
      for (let key in hour) {
         if (key !== 'workHour') {
           items.push({
              key: hour[key]
           })
         }
      }
   });
   result.chart.push({
      date: record.date,
      items
   });
});

console.log(result);

我要做的是遍历记录数组中的每个项目,然后遍历每个记录的小时数,将每个项目的所有值相加,例如计算所有小时数的总数,结果我我想得到的是:

array = [
  { 
    date: //record date,
    "Item name 1" : 314,
    "Item name 2" : 354,
    "Item name 3" : 364
  },
  { 
    date: //record date,
    "Item name 1" : 314,
    "Item name 2" : 354,
    "Item name 3" : 364
  },
  { 
    date: //record date,
    "Item name 1" : 314,
    "Item name 2" : 354,
    "Item name 3" : 364
  }
];

当时间项键已知时的工作示例:

const hours = [
{
    "workHour" : "8",
    "Item name 1" : 120,
    "Item name 2" : 149,
    "Item name 3" : 137
},
{
    "workHour" : "9",
    "Item name 1" : 134,
    "Item name 2" : 119,
    "Item name 3" : 144
},
{
    "workHour" : "10",
    "Item name 1" : 60,
    "Item name 2" : 86,
    "Item name 3" : 83
},

];

const records = [
   { date: new Date(), statistics: hours },
   { date: new Date(), statistics: hours },
   { date: new Date(), statistics: hours },
];

const result = {};
result.records = [];

const calculate = (profits, key) =>
  profits
  .filter(profit => profit !== null)
  .reduce((prevVal, profitVal) => prevVal + profitVal[key], 0) || 0;

records.forEach((record) => {
   const items = [];
   const { statistics } = record;
   result.records.push({
      date: record.date,
      'Item name 1': calculate(statistics, 'Item name 1'),
      'Item name 2': calculate(statistics, 'Item name 2'),
      'Item name 3': calculate(statistics, 'Item name 3'),
   });
});

console.log(result);

打印:

records = [


{
      'Item name 1': 314,
      'Item name 2': 354,
      'Item name 3': 364,
   },
   {
      'Item name 1': 314,
      'Item name 2': 354,
      'Item name 3': 364,
   },
   {
      'Item name 1': 314,
      'Item name 2': 354,
      'Item name 3': 364,
   },
]

【问题讨论】:

  • 你试图在array的每个对象上设置相同的值?
  • @guest271314 我正在尝试循环遍历所有时间,并且 += 对每个项目求和
  • 不关注。预期结果array 包含相同的对象?
  • @guest271314 在此示例中它们包含相同的结果,但结果来自按小时收集每个 Item 值。所以:记录->特定记录内的小时数->小时->小时内的3个项目。按小时对每一项求和...
  • 预期结果是items 数组对象,例如包含{key:134}?

标签: javascript arrays foreach ecmascript-6


【解决方案1】:

我相信这可以解决您的要求,但我觉得还有更多。 记录是否都打算具有相同的小时

我知道它有点密集,所以我添加了一些 cmets,希望能阐明它是如何工作的。

const hours = [
  { "workHour" : "8", "Item name 1" : 120, "Item name 2" : 149, "Item name 3" : 137 },
  { "workHour" : "9", "Item name 1" : 134, "Item name 2" : 119, "Item name 3" : 144 },
  { "workHour" : "10", "Item name 1" : 60, "Item name 2" : 86, "Item name 3" : 83 }
];

const records = [
   { date: new Date(), statistics: hours },
   { date: new Date(), statistics: hours },
   { date: new Date(), statistics: hours }
];

// ========================
// Using map()
// For each "record" return an object based on "record"
// ========================
var result = records.map(function(record){

  // ========================
  // Create the initial result that does not depend
  // on summing up the "statistics".
  //
  // We will pass this into the reduce() and it will be the
  // initial value of the accumulator
  // ========================
  var initialResult = {date: record.date};
  // ========================
  
  // ========================
  // Using reduce()
  // itterate over the interesting work items
  // summing up the hours
  // ========================
  var finalResult = record.statistics.reduce(function(acc, item){

    Object.keys(item)  // an array of keys in our item object
          .filter(function(key){ return key !== "workHour"; }) // remove this key
          .forEach(function(key) { acc[key] = (acc[key] || 0) + item[key] }); // for each remaining key, add its value to running total

    // ========================
    // return the running total accumulator for use against the next item
    // ========================
    return acc;
    // ========================

  }, initialResult);
  // ========================

  // ========================
  // return an object based on record but with accumulated data from the reduce()
  // this object becomes an item in the array ultimately returned by map()
  // ========================
  return finalResult;
  // ========================

});
// ========================

console.log(result)

这是一个没有reduce的版本:

const hours = [
  { "workHour" : "8", "Item name 1" : 120, "Item name 2" : 149, "Item name 3" : 137 },
  { "workHour" : "9", "Item name 1" : 134, "Item name 2" : 119, "Item name 3" : 144 },
  { "workHour" : "10", "Item name 1" : 60, "Item name 2" : 86, "Item name 3" : 83 }
];

const records = [
   { date: new Date(), statistics: hours },
   { date: new Date(), statistics: hours },
   { date: new Date(), statistics: hours }
];

var result = records.map(function(record){
  var initialResult = {date: record.date};

  record.statistics.forEach(function(item){
    Object.keys(item)
          .filter(function(key){ return key !== "workHour"; })
          .forEach(function(key) { initialResult[key] = (initialResult[key] || 0) + item[key] });
  });

  return initialResult;
});

console.log(result)

【讨论】:

  • @JasonBrill 我注意到您在另一个答案中表示我的方法有点令人困惑。我添加了一些 cmets,希望能让事情变得更清晰。
  • 非常感谢!为了解释只是想知道有没有办法在不减少的情况下实现这一目标?
  • 我加了一个不使用reduce()的版本
  • 谢谢!您建议使用 reduce 或不使用什么?
  • 两者都可以。在这种情况下,forEach() 似乎完全合理,甚至比 reduce() 更清晰。通常一个 reduce() 可以清理一个凌乱的 forEach() 但在这种情况下也许相反的是:-)
【解决方案2】:

如果正确解释问题,您可以将for..of 循环替换为.forEach(),使用计算属性名称[key] 设置推送到items 数组的对象的属性名称

const hours = [{
  "workHour": "8",
  "Item name 1": 120,
  "Item name 2": 149,
  "Item name 3": 137
}, {
  "workHour": "9",
  "Item name 1": 134,
  "Item name 2": 119,
  "Item name 3": 144
}, {
  "workHour": "10",
  "Item name 1": 60,
  "Item name 2": 86,
  "Item name 3": 83
}, ];

const records = hours.map((hour, index) => ({
    date: new Date(),
    statistics: hours[index]
  }));

const result = {};
result.chart = [];

records.forEach((record, index) => {
  const items = [];
  for (let {statistics:hour} of [record]) {
    for (let key in hour) {
    if (key !== 'workHour') {
        items.push({
          [key]: hour[key] 
                 + (result.chart[index -1] 
                      && result.chart[index -1].hasOwnProperty("items") 
                    ? result.chart[index-1].items
                      .filter(obj => obj.hasOwnProperty(key))[0][key] 
                    : 0)          
        })
      }
    }
  };
  result.chart.push({
    date: record.date,
    items
  });
});

console.log(result);

【讨论】:

  • 感谢您帮助我! JonSG 得到了我想要的结果,但我完全不明白他的方法.. 有没有简化的方法?
  • stacksn-ps 处的javascript 不会返回预期结果吗? jsfiddle.net/u950qf04/1?
  • 几乎,您的 items 数组包含额外的 [][] 两个数组,而不是直接,items -> Item 1, Item 2, Item3,就像@JonSG 所做的那样
  • 谢谢.. 只剩下一件事是 items 数组需要保存记录作为键,并且在该项目键值对内: items: [{ "date": "2016-11-11T21:32:47.533 Z", "项目名称 1": 314, "项目名称 2": 354, "项目名称 3": 364 }] 这样
  • 顺便说一句,如果 () 循环的性能提高 2 倍非常慢,JonSG 会回答。我在工作台上标有 console.time 两个选项..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-08
  • 2018-03-23
相关资源
最近更新 更多