首页 > 解决方案 > 对按键分组的对象数组的值求和并返回到新的数组数组中

问题描述

我需要对按两个属性分组的所有值求和:"date""zona". 特别是,我想翻译"date"成星期几,并按它分组。我"zona"想按“zona 1”、“zona 2”、“zona 3”等进行分组。

预期结果:

[dayOfWeek, zoneId, value];

[
   [0, 0, something],
   [0, 1, something],
   ...
   [0, 9, something],
   [1, 0, something],
   ...
   [6, 9, something]
]

我已经做了类似的事情(jsfiddle here):

数据初始化:

const data = [
  {
     "date": "2017/12/31",
     "ALL.new users": 298,
     "ALL.returning users": 12528,
     "zona 1.new users": 189,
     "zona 1.returning users": 3422,
     "zona 10.new users": 18,
     "zona 10.returning users": 2767,
     "zona 2.new users": 11,
     "zona 2.returning users": 1216,
     "zona 3.new users": 20,
     "zona 3.returning users": 3175,
     "zona 4.new users": 5,
     "zona 4.returning users": 1465,
     "zona 5.new users": 3,
     "zona 5.returning users": 1102,
     "zona 6.new users": 20,
     "zona 6.returning users": 2223,
     "zona 7.new users": 2,
     "zona 7.returning users": 1063,
     "zona 8.new users": 25,
     "zona 8.returning users": 1093,
     "zona 9.new users": 3,
     "zona 9.returning users": 1507
  }, {...}
];

const zoneMapping = {
   "Zone 1": 0,
   "Zone 2": 1,
   "Zone 3": 2,
   "Zone 4": 3,
   "Zone 5": 4,
   "Zone 6": 5,
   "Zone 7": 6,
   "Zone 8": 7,
   "Zone 9": 8,
   "Zone 10": 9
};

const dayMapping = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

功能:

let tempSeriesData = [];     

data.forEach(
   (item) => {
       const date = (new Date(item.date)).getDay();

       Object.entries(item).forEach(([key, value]) => {
           if (key !== "date" && key !== "ALL.new users" && key !== "ALL.returning users" && !key.includes("new users")) {
               let tempYValue = key.slice(0, 7).replace(".", "");
               tempYValue = tempYValue.replace("a", "e");
               const yValue = tempYValue.charAt(0).toLocaleUpperCase() + tempYValue.slice(1)
               const dataValue = Number(value);
               const element = [
                   date,
                   zoneMapping[yValue],
                   dataValue
               ];

               const existingElement = tempSeriesData.find(el => el[0] === element[0] && el[1] === element[1]);
               if (existingElement) {
                   existingElement[2] += element[2];
               }
               else {
                   tempSeriesData.push(element);
               }            
           }
       });
   }
);

有了这个功能,我可以获得我想要的东西,但我正在寻找一种新的方法来做同样的事情,也许使用 map()、reduce 或其他东西,因为我想改进这些方法的使用。

提前感谢您的回答。

标签: javascriptarrays

解决方案


其实没关系。代码是明确的,它做了它应该做的事情。如果我们真的想重构它,为了清楚起见,我会使用对象,然后稍后在数组中转换。另外我会使用 map/reduce 而不是全局 var + forEach 循环。

const parser = (item) => {
  const date = (new Date(item.date)).getDay();
  myItem = Object.entries(item).flatMap(([key, value]) => {
    key = key.split(/[\s.]+/) // split the key on SPACE and DOT at the same time
    // Maybe I misunderstand the IF from before but this works right now.
    return key[2] === "returning" ? [{ day: date, zone: key[1] - 1, value: Number(value) }] : []
  })
  return myItem
}

// upsert adds elements to the object if new or update existing
const upSert = (acc, { value, ...r }) => {
  key = JSON.stringify(r) // Since it is a nested map, we make our life easier with unique keys.
  acc[key] = (acc[key] || { ...r, value: 0 }); // if null initialize
  return (acc[key].value += value, acc) // update in place
}

const toValueArray = (data) => {
  return Object.values(data).map(d => Object.values(d))
}

//This could be already populated from a previous run
// Probably comming as a prop to a component
seriesData = {}

myTs = data.flatMap(parser)
  .reduce(upSert, seriesData)

const finalSeriesData = toValueArray(myTs)

推荐阅读