I have an array of quite simple objects:
[
{ category: 'A', level: 'Aa', sublevel: 'Aaa' },
{ category: 'A', level: 'Aa', sublevel: 'Aab' },
{ category: 'A', level: 'Ab', sublevel: 'Abb' },
{ category: 'B', level: 'Ac', sublevel: 'Abc' }
]
Sublevels are always unique, levels and categories can be same.
I want to create the following object from that array:
[
{
category: 'A',
children: [
{
level: 'Aa',
children: [
{
sublevel: 'Aaa'
},
{
sublevel: 'Aab'
}
]
},
{
level: 'Ab',
children: [
{
sublevel: 'Abb'
}
]
}
]
},
{
category: 'B',
children: [
{
level: 'Ac',
children: [
{
sublevel: 'Abc'
}] }] }]
In other words I want to merge category
into one if there are two objects with same category and place its levels into array children
. If there are also objects with same categories and levels, then merge same levels into one and place sublevels into relevant array children
.
Iterating through the array didn't really work out with [].map
and [].reduce
and various kinds of loops. Also tried lodash mergeWith and deepmerge, but sublevels seem to be invisible for them.
What are the elegant ways of constructing objects on conditions with more than 2 levels deep?
You just need a reducer with a nested filter/map on the original array.
const categories = base.reduce((accumulator, data) => {
let category;
if (!accumulator.find(d => d.category === data.category)) {
category = {
category: data.category,
children: [],
};
base
.filter(d => d.category === data.category)
.map(d => {
if (!category.children.find(c => c.level === d.level)) {
category.children.push({ level: d.level, children: [] });
}
const level = category.children.find(c => c.level === d.level);
if (!level.children.find(c => c.sublevel === d.sublevel)) {
level.children.push({ sublevel: d.sublevel });
}
})
accumulator.push(category);
}
return accumulator;
}, []);