I want to build a JSON object from an array returned from http request my actual array look like:
[{
Description: "Product"
IsInstanciable: false
IsMasked: false
Name: "ProductBase"
Subclasses: [{
Description: "Product2"
IsInstanciable: false
IsMasked: false
Name: "ProductBase2",
Count: 5,
Subclasses:[]
},
{
Description: "Product3"
IsInstanciable: false
IsMasked: false
Name: "ProductBase3",
Count: 4,
Subclasses:[],
}]
},
{
Description: "Product4"
IsInstanciable: false
IsMasked: false
Name: "ProductBase4",
Count: '...',
Subclasses: [...]
}
I want to create a JSON object recursively from the array above. It will look like this:
[
{
name: 'Product',
Count: 9,
children: [
{name: 'Product2'},
{name: 'Product3'},
]
}, {
name: 'Product4',
children: [
{
name: '...',
Count: 'Sum of Count in all children by level'
children: [
{name: '...'},
{name: '...'},
]
}
]
},
];
Here is my recursively function in typescript but it doesn't work as expected. How can I fix this?
recursive(data, stack: TreeNode[]) {
let elt: TreeNode = {name:'', children: []}
if(data.Subclasses.length > 0) {
elt.name = data.Description;
data.Subclasses.forEach(element => {
elt.children.push({name: element.Description});
this.recursive(element, stack);
});
}else {
elt.name = data.Description;
}
stack.push(elt);
}
You can use the map function together with the recursive function like this:
function MapObject(object) {
if(!object || object.length < 0) return [];
return object.map(obj => { return {
name: obj.Description,
children: MapObject(obj.Subclasses)
}});
}
Follows a full work example:
var example = [{
Description: "Product",
IsInstanciable: false,
IsMasked: false,
Name: "ProductBase",
Subclasses: [{
Description: "Product2",
IsInstanciable: false,
IsMasked: false,
Name: "ProductBase2",
Subclasses:[]
},
{
Description: "Product3",
IsInstanciable: false,
IsMasked: false,
Name: "ProductBase3",
Subclasses:[]
}]
},
{
Description: "Product4",
IsInstanciable: false,
IsMasked: false,
Name: "ProductBase4"
}]
function MapObject(object) {
if(!object || object.length < 0) return [];
return object.map(obj => { return {
name: obj.Description,
children: MapObject(obj.Subclasses)
}});
}
console.log(MapObject(example));
I would break this down into a few separate functions with clear responsibilities:
const sum = (ns) =>
ns .reduce ((a, b) => a + Number (b), 0)
const getCount = (product) =>
(product .Count || 0) + sum ((product .Subclasses || []) .map (getCount))
const extract = (product) =>
({
name: product .Name,
count: getCount (product),
children: product .Subclasses .map (extract)
})
const extractAll = (products) =>
products .map (extract)
const products = [{"Description": "Product", "IsInstanciable": false, "IsMasked": false, "Name": "ProductBase", "Subclasses": [{"Count": 5, "Description": "Product2", "IsInstanciable": false, "IsMasked": false, "Name": "ProductBase2", "Subclasses": []}, {"Count": 4, "Description": "Product3", "IsInstanciable": false, "IsMasked": false, "Name": "ProductBase3", "Subclasses": []}]}, {"Count": 3, "Description": "Product4", "IsInstanciable": false, "IsMasked": false, "Name": "ProductBase4", "Subclasses": []}]
console .log (
extractAll (products)
)
(Note that I changed the case of the output count
property. It just seemed more consistent with name
and children
.)
We recur through the object to get its Count
property, and we recur separately to get the rest of the object. While there might be a way to combine these, I would expect that the code would be significantly more complex.
Note that I assumed that all Count
properties are actually numeric, although your example above includes a string. If you do have values like "3"
, then getCount
will need to be a little more sophisticated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With