Reputation: 1209
I've got an object that looks like this:
{
parent: {
child1: {
key: 'value'
},
child2: {
key: 'value'
},
child3: {
key: 'value'
}
}
}
I need to transform it to an object that looks like this:
{
title: 'parent',
children: [{
title: 'child1',
children: [{
title: 'key',
value: 'value'
}]
}, {
title: 'child2',
children: [{
title: 'key',
value: 'value'
}]
}, {
title: 'child3',
children: [{
title: 'key',
value: 'value'
}]
}]
}
I ended up with a following function:
function transform(obj) {
const result = {
title: '',
children: []
};
for (let key in obj) {
let child = obj[key];
result.title = key;
if (typeof(child) === 'string') {
delete result.children;
result.value = child;
} else {
result.children.push(transform(child));
}
}
return result;
}
But when I run it, it returns me the following output, which is wrong:
{
title: 'parent',
children: [{
title: 'child3',
children: [
{ title: 'key', value: 'value' },
{ title: 'key', value: 'value' },
{ title: 'key', value: 'value' }
]
}]
}
Could anyone point out what exactly is my mistake in the function, please?
Upvotes: 1
Views: 113
Reputation: 50797
While the recursion here is fairly simple, you have an odd requirement. What would you expect if the root node had multiple properties?
I handle this with a wrapper function which uses the recursive one to build an array of similar nodes, but then takes only the first result. This seems far from ideal, but it works:
const _transform = (obj) =>
Object .entries (obj) .map (([k, v]) => ({
title: k,
...(Object (v) === v ? {children: _transform (v)} : {value: v})
}))
const transform = (obj) => _transform (obj) [0]
const input = {parent: {child1: {key: 'value'}, child2: {key: 'value'}, child3: {key: 'value'}}}
console .log (transform (input))
.as-console-wrapper {min-height: 100% !important; top: 0}
This code would be simpler with the API suggested by Bergi. This is the same idea as that code but with an implementation in my style:
const transform = (title, value) =>
Object (value) === value
? {title, children: Object .entries (value) .map (([k, v]) => transform (k, v))}
: {title, value}
const input = {parent: {child1: {key: 'value'}, child2: {key: 'value'}, child3: {key: 'value'}}}
console .log (
transform ('parent', input.parent)
)
.as-console-wrapper {min-height: 100% !important; top: 0}
Upvotes: 0
Reputation: 664579
I think you've chosen the wrong base case for the tree recursion. Put the leaf detection at the top of the function, not in the loop:
function transform(title, value) {
if (typeof value === 'string') {
return {title, value};
} else {
const children = [];
for (let key in obj) {
children.push(transform(key, obj[key]));
}
return {title, children};
}
}
Since you only want the single child of the root node, you'd call it as
console.log(transform('parent', data.parent));
or
console.log(transform('', data).children[0]);
Upvotes: 2
Reputation: 1142
Here is what you want:
const o = {
parent: {
child1: {
key: 'value'
},
child2: {
key: 'value'
},
child3: {
key: 'value'
}
}
};
const r = {};
const struct = (root, c) => {
Object.entries(root).map(([k, v]) => {
if (typeof v === 'object') {
const el = { title: k, children: [] };
c.push(el);
struct(v, el.children);
} else {
c.push({ title: k, value: v });
}
});
}
r.title = 'parent';
r.children = [];
struct(o.parent, r.children);
console.log(r);
Upvotes: 1