简体   繁体   English

按键分组的对象数组的总和值并返回到新的数组数组中

[英]Sum values of array of object grouped by keys and return into a new array of arrays

I need to sum all values grouped by two properties: "date" and "zona" .我需要对按两个属性分组的所有值求和: "date""zona" In particular, I want to translate "date" into day of week, and group by it.特别是,我想将"date"翻译成星期几,并按它分组。 With "zona" I want to group by "zona 1", "zona 2, "zona 3" and so on.对于"zona"我想按“zona 1”、“zona 2”、“zona 3”等分组。

Expected result:预期结果:

[dayOfWeek, zoneId, value];

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

I already did something like that (jsfiddle here ):我已经做了类似的事情(这里是jsfiddle):

Data init:数据初始化:

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"];

Function:功能:

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);
               }            
           }
       });
   }
);

With this function I able to obtain what I want, but I am looking into a new method to do the same thing, maybe using, map(), reduce or something, 'cause I want to improve the use of these methods.有了这个函数,我可以获得我想要的东西,但我正在寻找一种新方法来做同样的事情,也许使用 map()、reduce 或其他东西,因为我想改进这些方法的使用。

Thanks for your answers in advance.提前感谢您的回答。

It's fine actually.其实还好The code is explicit and it does what it should.代码是明确的,它做了它应该做的。 If we really want to refactor this, I'd work with objects for clarity and then transform in array later.如果我们真的想重构它,为了清晰起见,我会使用对象,然后在数组中进行转换。 Also I'd use map/reduce instead of a global var + forEach loop.另外我会使用 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM