I need some help doing a dataset transformation.
I have this array of objects:
const CATEGORY = "category";
const DATE = "date";
const dataset = [
{ date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
{ date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
{ date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
{ date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
{ date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
{ date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
{ date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
{ date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
{ date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];
And I need:
const result = [
{ "date": "2012", "pizza": 1, "fruit": 3, "pasta": 2 },
{ "date": "2013", "pizza": 1, "fruit": 3, "pasta": 1 },
{ "date": "2014", "pizza": 2, "fruit": 2, "pasta": 1 }
]
So an array of objects, one for each date. The keys of this object should be the date and all the categories with their value of column kpi
.
To do that I create this function:
function formatDataset(dataset, kpi) {
const categories = uniqBy(dataset, CATEGORY).map((d) => d[CATEGORY]);
const groupByDate = groupBy(dataset, DATE);
const dates = Object.keys(groupByDate);
const result = dates.map((date) => {
return groupByDate[date].reduce((acc, datum, accI) => {
acc = {
...acc,
[datum[CATEGORY]]: datum[kpi] || 0,
[DATE]: date
};
return acc;
}, {});
});
return result;
}
It works, I don't know if there is a better way to do that but, anyway, it works.
The problem is that dataset
may not have all the data, for example:
const dataset = [
{ date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
// { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
{ date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
{ date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
{ date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
{ date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
{ date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
{ date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
{ date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];
In that case the result is this:
[
{ "pizza": 1, "date": "2012", "pasta": 2 },
{ "pizza": 1, "date": "2013", "fruit": 3, "pasta": 1 },
{ "pizza": 2, "date": "2014", "fruit": 2, "pasta": 1 }
]
but it should be:
[
{ "pizza": 1, "date": "2012", "fruit": 0, "pasta": 2 },
{ "pizza": 1, "date": "2013", "fruit": 3, "pasta": 1 },
{ "pizza": 2, "date": "2014", "fruit": 2, "pasta": 1 }
]
How can I fix the function?
Here the code:
import * as _ from 'lodash';
const CATEGORY = "category";
const DATE = "date";
function flatize(dataset, kpi) {
console.log("\n-- flatize --");
const categories = uniqBy(dataset, CATEGORY).map((d) => d[CATEGORY]);
console.log("categories: ", categories);
const groupByDate = groupBy(dataset, DATE);
console.log("groupByDate: ", groupByDate);
const dates = Object.keys(groupByDate);
console.log("dates: ", dates);
const flatizedDataset = dates.map((date) => {
return groupByDate[date].reduce((acc, datum, accI) => {
console.log("- accI: ", accI);
console.log(" datum: ", datum);
console.log(" datum[CATEGORY]: ", datum[CATEGORY]);
acc = {
...acc,
[datum[CATEGORY]]: datum[kpi] || 0,
[DATE]: date
};
return acc;
}, {});
});
return flatizedDataset;
}
const dataset = [
{ date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
// { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
{ date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
{ date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
{ date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
{ date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
{ date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
{ date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
{ date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];
const flatDataset = flatize(dataset, "valueA");
console.log("dataset:", dataset);
console.log("flatDataset:", flatDataset);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
CodePudding user response:
Try this
const normalize = (data, key) => {
let resultObj = {};
data.forEach(item => {
resultObj[item.date] = {
pizza: 0,
fruit: 0,
pasta: 0,
...resultObj[item.date] || {},
date: item.date,
[item.category]: item[key]
};
});
return Object.values(resultObj);
}
CodePudding user response:
Here is a non lodash solution. What to take from here is I'm creating an initializer
which will look like {pizza: 0, fruit: 0,....}
depending on the unique categories and then I'm setting a copy of it inside the reduce
for every new group by date
const dataset = [ { date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 }, { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 }, { date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 }, { date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 }, { date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 }, { date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }, { date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 }, { date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 }, { date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }];
function flatize(dataset, kpi) {
const uniqCategories = [...new Set(dataset.map(({category})=>category))]
const initializer = Object.fromEntries(uniqCategories.map((c) => [c,0]))
const groupedByDate = dataset.reduce((acc,{date,category,[kpi]:value})=>{
acc[date] = acc[date]||{date,...initializer}
acc[date][category] = value
return acc
},{})
return Object.values(groupedByDate)
}
console.log(flatize(dataset,'valueC'))
same change can be added to your implementation as well
const CATEGORY = "category";
const DATE = "date";
function flatize(dataset, kpi) {
const categories = _.uniqBy(dataset, CATEGORY).map((d) => d[CATEGORY]);
const groupByDate = _.groupBy(dataset, DATE);
const initializer = Object.fromEntries(categories.map((c) => [c,0]))
const dates = Object.keys(groupByDate);
const flatizedDataset = dates.map((date) => {
return groupByDate[date].reduce((acc, datum, accI) => {
acc = {
...initializer,
...acc,
[datum[CATEGORY]]: datum[kpi] || 0,
[DATE]: date
};
return acc;
}, {});
});
return flatizedDataset;
}
const dataset = [
{ date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
// { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
{ date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
{ date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
{ date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
{ date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
{ date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
{ date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
{ date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];
const flatDataset = flatize(dataset, "valueA");
console.log(flatDataset);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>