Reputation: 1409
I have input data structure like
const i = [
{ Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 12 },
{ Time: "Breakfast", City: "Hyderabad", Area: "LBNagar", count: 19 },
{ Time: "Lunch", City: "Bangalore", Area: "Koramangala", count: 22 },
{ Time: "Dinner", City: "Hyderabad", Area: "Koti", count: 10 },
{ Time: "Dinner", City: "Bangalore", Area: "Bellandur", count: 16 },
{ Time: "Lunch", City: "Hyderabad", Area: "LBNagar", count: 28 },
{ Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 11 },
{ Time: "Lunch", City: "Hyderabad", Area: "Koti", count: 24 },
{ Time: "Dinner", City: "Bangalore", Area: "Koramangala", count: 27 },
{ Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 22 },
{ Time: "Breakfast", City: "Hyderabad", Area: "Manikonda", count: 11 },
{ Time: "Dinner", City: "Hyderabad", Area: "Manikonda", count: 10 },
{ Time: "Lunch", City: "Bangalore", Area: "Bellandur", count: 17 }
];
Expected transformed data structure should be nested array with count
prop equals to sum of children's count
value
[
{
"d": "Breakfast",
"count": 42,
"children": [
{
"d": "Bangalore",
"count": 12,
"children": [
{
"d": "Bellandur",
"count": 12,
"children": []
}
]
},
{
"d": "Hyderabad",
"count": 30,
"children": [
{
"d": "LBNagar",
"count": 19,
"children": []
},
{
"d": "Manikonda",
"count": 11,
"children": []
}
]
}
]
},
{
"d": "Lunch",
"count": 91,
"children": [
{
"d": "Bangalore",
"count": 39,
"children": [
{
"d": "Koramangala",
"count": 22,
"children": []
},
{
"d": "Bellandur",
"count": 17,
"children": []
}
]
},
{
"d": "Hyderabad",
"count": 52,
"children": [
{
"d": "LBNagar",
"count": 28,
"children": []
},
{
"d": "Koti",
"count": 24,
"children": []
}
]
}
]
},
{
"d": "Dinner",
"count": 63,
"children": [
{
"d": "Hyderabad",
"count": 20,
"children": [
{
"d": "Koti",
"count": 10,
"children": []
},
{
"d": "Manikonda",
"count": 10,
"children": []
}
]
},
{
"d": "Bangalore",
"count": 43,
"children": [
{
"d": "Bellandur",
"count": 16,
"children": []
},
{
"d": "Koramangala",
"count": 27,
"children": []
}
]
}
]
}
]
To achieve above result, I have snippet
const input = [
{ Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 12 },
{ Time: "Breakfast", City: "Hyderabad", Area: "LBNagar", count: 19 },
{ Time: "Lunch", City: "Bangalore", Area: "Koramangala", count: 22 },
{ Time: "Dinner", City: "Hyderabad", Area: "Koti", count: 10 },
{ Time: "Dinner", City: "Bangalore", Area: "Bellandur", count: 16 },
{ Time: "Lunch", City: "Hyderabad", Area: "LBNagar", count: 28 },
{ Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 11 },
{ Time: "Lunch", City: "Hyderabad", Area: "Koti", count: 24 },
{ Time: "Dinner", City: "Bangalore", Area: "Koramangala", count: 27 },
{ Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 22 },
{ Time: "Breakfast", City: "Hyderabad", Area: "Manikonda", count: 11 },
{ Time: "Dinner", City: "Hyderabad", Area: "Manikonda", count: 10 },
{ Time: "Lunch", City: "Bangalore", Area: "Bellandur", count: 17 }
];
// convert nested array into map
// Ex: {Breakfast: { Bangalore: {Bellandur: 40 }, ... } ... }}}
const nestedMap = input.reduce((acc, v) => {
if (!acc[v["Time"]]) {
acc[v["Time"]] = {};
}
if (!acc[v["Time"]][v["City"]]) {
acc[v["Time"]][v["City"]] = {};
}
if (!acc[v["Time"]][v["City"]][v["Area"]]) {
acc[v["Time"]][v["City"]][v["Area"]] = v["count"];
}
return acc;
}, {});
const summer = (o, i) =>
typeof o === "number"
? i + o
: Object.values(o).reduce((acc, v) => acc + summer(v, i), 0);
const aggregator = o => {
return typeof o === "number"
? []
: Object.entries(o).map(([n, child]) => ({
d: n,
count: summer(child, 0),
children: aggregator(child)
}));
};
const result = aggregator(nestedMap);
console.log(JSON.stringify(result, undefined, 2));
Thought my snippet working perfectly, It involves lot of iterations. First converting into map and one iteration (summer
function) to get count of children and other iteration (aggregator
function) to form nested array.
I am looking for better performant solution. Thanks in advance!
Upvotes: 1
Views: 96
Reputation: 386680
You could take a more concise approach with an array of the nested keys and seach for the object with the value at the level.
Then add count and return the actual object.
This approach prevents tailing children arrays
var data = [{ Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 12 }, { Time: "Breakfast", City: "Hyderabad", Area: "LBNagar", count: 19 }, { Time: "Lunch", City: "Bangalore", Area: "Koramangala", count: 22 }, { Time: "Dinner", City: "Hyderabad", Area: "Koti", count: 10 }, { Time: "Dinner", City: "Bangalore", Area: "Bellandur", count: 16 }, { Time: "Lunch", City: "Hyderabad", Area: "LBNagar", count: 28 }, { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 11 }, { Time: "Lunch", City: "Hyderabad", Area: "Koti", count: 24 }, { Time: "Dinner", City: "Bangalore", Area: "Koramangala", count: 27 }, { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 22 }, { Time: "Breakfast", City: "Hyderabad", Area: "Manikonda", count: 11 }, { Time: "Dinner", City: "Hyderabad", Area: "Manikonda", count: 10 }, { Time: "Lunch", City: "Bangalore", Area: "Bellandur", count: 17 }],
keys = ['Time', 'City', 'Area'],
result = data
.reduce((r, o) => {
keys.reduce((p, k) => {
var temp = (p.children = p.children || []).find(q => q.d === o[k]);
if (!temp) p.children.push(temp = { d: o[k], count: 0 });
temp.count += o.count;
return temp;
}, r);
return r;
}, { children: [] })
.children;
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1