javascript - 如何找到项目的总和并动态创建新对象?

标签 javascript object ecmascript-6

如何根据以下数据建模与目标对象类似的对象?如果 ES6 中存在简写,那么它会更合适。

数据样本包含人员及其收集的元素的信息。Max和Carol收集了具有不同值的相同石头。如果发生这种情况,则应将其作为新元素推送到我们的目标对象中。

示例数据

let people = [{
  "id": 1,                        // Person Id
  "name": "John",                 // Name of person
  "date": "2017-5-27",            // Date
  "totalAssets": 500,             // Sum of total (gems collected)
  "gems": [{                      // Gems collected from forest
    "total": 500,           // totalCollected * value
    "value": 100,           // Value of one gem (Ruby = 100)
    "totalCollected": 5,    // Total number
    "gemName": "Ruby",      // Gem name
    "gemCode": "GEM001"     // Gem code
  }]
}, {
  "id": 2,
  "name": "Max",
  "date": "2017-5-28",
  "totalAssets": 1300, // TotalAssets = Emerald.total + Moonstone.total
  "gems": [{
    "total": 900,
    "value": 150,
    "totalCollected": 6,
    "gemName": "Emerald",
    "gemCode": "GEM002"
  }, {
    "total": 400,
    "value": 250,
    "totalCollected": 2,
    "gemName": "Moonstone",
    "gemCode": "GEM003"
  }]
}, {
  "id": 3,
  "name": "Carol",
  "date": "2017-5-29",
  "totalAssets": 2900,
  "gems": [{
      "total": 1500,
      "value": 150,
      "totalCollected": 10,
      "gemName": "Emerald",
      "gemCode": "GEM002"
    }, {
      "total": 1000,
      "value": 200,
      "totalCollected": 5,
      "gemName": "Moonstone",
      "gemCode": "GEM003"
    },
    {
      "total": 400,
      "value": 100,
      "totalCollected": 4,
      "gemName": "Ruby",
      "gemCode": "GEM001"
    }
  ]
}]

计算总计

computeTotal = () => {   //Mock target object function
 // Return target object

   "totalAssets": 4800, //Total assets of all people
   "gemsValueTotal":[{
     "gemName": "Ruby",
     "value": 100,
     "totalC0llected":9,
     "total": 900,
   },
   {
     "gemName": "Emerald",
     "value": 150,
     "totalC0llected":16,
     "total": 2400,
   },
   {
     "gemName": "MoonStone",
     "value": 200,
     "totalC0llected":5,
     "total": 1000,
   },
   {
     "gemName": "MoonStone", // Value changed so push as new item in object
     "value": 250,
     "totalC0llected":2,
     "total": 500,
   }
   ]
}

我通过这种方式找到了一些解决方案。

 aggregateGems(data) {
   this.rows = [];
   let totalCollected = 0;
   let totalvalue = 0;
   return data.filter((item) => {
       item.gems.map(d => {
        let model: any = {};
        let totalAssets: number = 0;
        totalCollected += parseInt(d.totalCollected);
        totalvalue += parseInt(d.total);
        model.gemname = d.gemName;
        model.value = d.value;
        model.totalCollected = totalCollected;
        model.totalValue = totalValue;
        this.rows.push(model);
        debugger
       });
     },
   );
 }

最佳答案

您可以使用 Array.reduce 来完成此操作功能,与 Array.forEach 合作功能。

// this will save the indexes of the gemNames and value in the output array (so you don't have to search for the index all of the time)
let gemNameValueIndex = {};
// this will reduce the people array in a new object, receiving the new object and the next person on each iteration
let totals = people.reduce( (current, person) => {

  // and for each person we need to iterate the gems
  person.gems.forEach( gem => {
    // each gem increases the total value
    current.totalAssets += gem.total;
    let key = gem.gemName + gem.value;
    let idx;
    if ((idx = gemNameValueIndex[key]) === undefined) {
      // no matching gem found, so add the index
      current.gemsValueTotal.push( { 
        gemName: gem.gemName,
        value: gem.value,
        totalCollected: gem.totalCollected,
        total: gem.total
      } );
      // mark the index so it can be looked up for next iterations
      gemNameValueIndex[key] = current.gemsValueTotal.length - 1;
      return;
    }
    // update the already found index with the new totals
    current.gemsValueTotal[idx].totalCollected += gem.totalCollected;
    current.gemsValueTotal[idx].total += gem.total;
  });

  return current;
}, { totalAssets: 0, gemsValueTotal: [] } );

您的totals对象现在将包含您正在查找的数据(您可以在下面的代码片段中尝试一下)。

gemNameValueIndex将包含每个值的 gem 作为键以及生成的总对象中的索引(但该对象的存在只是为了避免循环 gemsValueTotal 中所有添加的 gem ,以根据我们需要比较的 gemName 和每个 gem 的值查找索引)

let people = [{
  "id": 1,                        // Person Id
  "name": "John",                 // Name of person
  "date": "2017-5-27",            // Date
  "totalAssets": 500,             // Sum of total (gems collected)
  "gems": [{                      // Gems collected from forest
    "total": 500,           // totalCollected * value
    "value": 100,           // Value of one gem (Ruby = 100)
    "totalCollected": 5,    // Total number
    "gemName": "Ruby",      // Gem name
    "gemCode": "GEM001"     // Gem code
  }]
}, {
  "id": 2,
  "name": "Max",
  "date": "2017-5-28",
  "totalAssets": 1300, // TotalAssets = Emerald.total + Moonstone.total
  "gems": [{
    "total": 900,
    "value": 150,
    "totalCollected": 6,
    "gemName": "Emerald",
    "gemCode": "GEM002"
  }, {
    "total": 400,
    "value": 250,
    "totalCollected": 2,
    "gemName": "Moonstone",
    "gemCode": "GEM003"
  }]
}, {
  "id": 3,
  "name": "Carol",
  "date": "2017-5-29",
  "totalAssets": 2900,
  "gems": [{
      "total": 1500,
      "value": 150,
      "totalCollected": 10,
      "gemName": "Emerald",
      "gemCode": "GEM002"
    }, {
      "total": 1000,
      "value": 200,
      "totalCollected": 5,
      "gemName": "Moonstone",
      "gemCode": "GEM003"
    },
    {
      "total": 400,
      "value": 100,
      "totalCollected": 4,
      "gemName": "Ruby",
      "gemCode": "GEM001"
    }
  ]
}];

// this will save the indexes of the gemNames and value in the output array (so you don't have to search for the index all of the time)
let gemNameValueIndex = {};
// this will reduce the people array in a new object, receiving the new object and the next person on each iteration
let totals = people.reduce( (current, person) => {
  
  // and for each person we need to iterate the gems
  person.gems.forEach( gem => {
    // each gem increases the total value
    current.totalAssets += gem.total;
    let key = gem.gemName + gem.value;
    let idx;
    if ((idx = gemNameValueIndex[key]) === undefined) {
      // no matching gem found, so add the index
      current.gemsValueTotal.push( { 
        gemName: gem.gemName,
        value: gem.value,
        totalCollected: gem.totalCollected,
        total: gem.total
      } );
      // mark the index so it can be looked up for next iterations
      gemNameValueIndex[key] = current.gemsValueTotal.length - 1;
      return;
    }
    // update the already found index with the new totals
    current.gemsValueTotal[idx].totalCollected += gem.totalCollected;
    current.gemsValueTotal[idx].total += gem.total;
  });
  
  return current;
}, { totalAssets: 0, gemsValueTotal: [] } );

console.log( totals );

关于javascript - 如何找到项目的总和并动态创建新对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44427242/

相关文章:

javascript - 为什么此 yargs 脚本帮助页面中缺少命令?

javascript - 驼峰字符串转普通字符串

java - 如何更改 Java 中的特定变量?

java - 在 Java 中有效地复制数组

javascript - 如何在 Angular Material 中固定 mat-select-panel 的位置

javascript - 通过AJAX发送文件返回 'blob'错误

javascript - 过滤嵌套对象

angular - 是否可以在 Typescript 中按值 "filter"映射?

javascript - 确定数组是等差级数还是等比级数(来自 Coderbyte)

javascript - 检查变量是否未定义