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:
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.
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);
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);