I am trying to populate a graph and the data has to be formatted a specific way. I finally got the data into the correct shape but I realized I am missing values.
so I have an array of dates:
const labels = ["Sep.08", "Sep.09", "Sep.12", "Sep.13", "Sep.14"]
and I have an array of objects that contain a name
and that date
along with a count
:
const Data = [
{date: "Sep.08", name: "User1", count: 8},
{date: "Sep.08", name: "User2", count: 2},
{date: "Sep.09", name: "User2", count: 3},
{date: "Sep.09", name: "User3", count: 1},
{date: "Sep.12", name: "User1", count: 11},
{date: "Sep.13", name: "User1", count: 3},
{date: "Sep.13", name: "User2", count: 3},
{date: "Sep.14", name: "User2", count: 7},
]
What I am trying to accomplish:
- Each Name should have an array in the new Object
- Each date should be represented in the arrays so that each Array is the same length. If the user does not have an object that represents one of the dates in the labels array then a zero should be added at that index in the new array.
My Expected Outcome would be:
const result = {
User1: [8,0,11,3,0], //0's where user has no object with the dates of "Sep.09" & "Sep.14"
User2: [2,3,0,3,7],
User3: [0,1,0,0,0],
}
I am using .reduce
to create my new Object:
const Data = [
{date: "Sep.08", name: "User1", count: 8},
{date: "Sep.08", name: "User2", count: 2},
{date: "Sep.09", name: "User2", count: 3},
{date: "Sep.09", name: "User3", count: 1},
{date: "Sep.12", name: "User1", count: 11},
{date: "Sep.13", name: "User1", count: 3},
{date: "Sep.13", name: "User2", count: 3},
{date: "Sep.14", name: "User2", count: 7},
]
const labels = ["Sep.08", "Sep.09", "Sep.12", "Sep.13","Sep.14"]
const groups = Data.reduce((acc, obj) => {
if (!acc[obj.name]) {
acc[obj.name] = [];
}
acc[obj.name].push(obj.count);
return acc;
}, {});
console.log(groups)
The issue is Im not sure how to compare the labels to the name in the acc object. Reduce is very confusing for me but it seems like the cleanest way to format the data how I need. Any advice would be helpful.
CodePudding user response:
You could do something like this:
const Data = [{date:"Sep.08",name:"User1",count:8},{date:"Sep.08",name:"User2",count:2},{date:"Sep.09",name:"User2",count:3},{date:"Sep.09",name:"User3",count:1},{date:"Sep.12",name:"User1",count:11},{date:"Sep.13",name:"User1",count:3},{date:"Sep.13",name:"User2",count:3},{date:"Sep.14",name:"User2",count:7},];
const labels = ["Sep.08","Sep.09","Sep.12","Sep.13","Sep.14"];
const groups = Data.reduce((acc, { date, name, count }) => {
if (!acc[name]) {
// Fill an array with zeroes, the length of labels
acc[name] = labels.map(_ => 0);
}
// Find the index of the current label
const labelIndex = labels.indexOf(date);
// Replace the corresponding zero
acc[name][labelIndex] = count;
return acc;
}, {});
console.log(groups);
CodePudding user response:
I would go for a first loop to find all the dates and users. Then for each date, loop on the users to build their array.
const dictionary = {};
const users = new Set();
Data.forEach(({date, name, count}) => {
if (!dictionary[date]) dictionary[date] = {};
// for each date, store users and their count when available
dictionary[date] = {[name]: count};
// keep track of existing users
users.add(name);
}
const result = {};
// convert the user set to an array
const userArray = Array.from(users);
// populate an array of count for each user
userArray.forEach(user => result[user] = []);
Object.entries(dictionary).forEach(([date, userCountMap]) => {
userArray.forEach(user => {
// for each date, populate the count of each user, or put 0 if there is no count
result[user].push(userCountMap[user] || 0);
});
});
console.log(result);