Reputation: 787
I need to sum all values grouped by two properties: "date"
and "zona"
.
In particular, I want to translate "date"
into day of week, and group by it.
With "zona"
I want to group by "zona 1", "zona 2, "zona 3" and so on.
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):
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.
Thanks for your answers in advance.
Upvotes: 0
Views: 65
Reputation: 1049
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.
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)
Upvotes: 1