const data = [
{ id: 1, type: 'type 1' },
{ id: 2, type: 'type 2', subtype: 'subtype 2' },
{ id: 3, type: 'type 2', subtype: 'subtype 3' },
{ id: 4, type: 'type 2', subtype: 'subtype 4' },
{ id: 5, type: 'type 3', subtype: 'subtype 3' },
];
console.log(
'pure object based tree ...',
data
.reduce((result, { type, subtype = null }) => {
const typeGroup = (result[type] ??= {});
if (subtype !== null) {
typeGroup[subtype] = {};
}
return result;
}, {})
)
console.log(
'object and array item based tree ...',
data
.reduce((result, { type, subtype = null }) => {
const groupedSubtypeList = (result[type] ??= []);
if (subtype !== null) {
groupedSubtypeList.push(subtype);
}
return result;
}, {})
)
console.log(
'what the OP probably is looking for ...',
Object
.entries(
// same reduce functionality as one example before.
data
.reduce((result, { type, subtype = null }) => {
const groupedSubtypeList = (result[type] ??= []);
if (subtype !== null) {
groupedSubtypeList.push(subtype);
}
return result;
}, {})
)
// additional mapping over the reduce result's entries.
.map(([type, subtypes]) => {
const typeItem = {
type: type.replace('type', '').trim(),
};
if (subtypes.length >= 1) {
typeItem.subtypes = subtypes
.map(subtype => ({
subtype: subtype.replace('subtype', '').trim(),
}));
}
return typeItem;
})
)
.as-console-wrapper { min-height: 100%!important; top: 0; }