I have a JSON object with nested children that I would like to flatten and modify using lodash. Ideally the revised JSON will have a value for the original level the nested children were at and show their original path.
Here is sample JSON:
var data = [
{id: 0, name: 'Australia', children: [
{id: 10, name: 'Melbourne', children: []},
{id: 11, name: 'Sydney', children: [
{id: 100, name: 'Surry Hills', children: []},
{id: 102, name: 'Darlinghurst', children: []}
]},
{id: 13, name: 'Kambalda', children: []}
]},
{id: 1, name: 'Spain', children: [
{id: 20, name: 'Barcelona', children: []},
{id: 21, name: 'Madrid', children: []}
]},
{id: 3, name: 'UK', children: [
{id: 30, name: 'London', children: [
{id: 302, name: 'Knightsbridge', children: []},
{id: 309, name: 'West End', children: []}
]},
{id: 33, name: 'Leeds', children: []},
{id: 35, name: 'Manchester', children: []}
]}
];
And the transformed JSON I would like to generate is:
[
{id: 0, name: 'Australia', level: 0, pathname: 'Australia'},
{id: 10, name: 'Melbourne', level: 1, pathname: 'Australia > Melbourne'},
{id: 11, name: 'Sydney', level: 1, pathname: 'Australia > Sydney'},
{id: 100, name: 'Surry Hills', level: 2, pathname: 'Australia > Sydney > Surry Hills'},
{id: 102, name: 'Darlinghurst', level: 2, pathname: 'Australia > Sydney > Darlinghurst'},
{id: 13, name: 'Kambalda', level: 1, pathname: 'Australia > Kambalda'},
{id: 1, name: 'Spain', level: 0, pathname: 'Spain'},
{id: 20, name: 'Barcelona', level: 1, pathname: 'Spain > Barcelona'},
{id: 21, name: 'Madrid', level: 1, pathname: 'Spain > Madrid'},
{id: 3, name: 'UK', level: 0, pathname: 'UK'},
{id: 30, name: 'London', level: 1, pathname: 'UK > London'},
{id: 302, name: 'Knightsbridge', level: 2, pathname: 'UK > London > Knightsbridge'},
{id: 309, name: 'West End', level: 2, pathname: 'UK > London > West End'},
{id: 33, name: 'Leeds', level: 1, pathname: 'UK > Leeds'},
{id: 35, name: 'Manchester', level: 1, pathname: 'UK > Manchester'}
]
I have been playing with _.chain, _.flatten and _.pluck and been unable to get anything close.
You can use a simple recursive helper function that would produce an array of arrays, and then use _.flattenDeep
to flatten it. This does what you want:
function flattenMyTree(tree) {
function recurse(nodes, path) {
return _.map(nodes, function(node) {
var newPath = _.union(path, [node.name]);
return [
_.assign({pathname: newPath.join(' > '), level: path.length}, _.omit(node, 'children')),
recurse(node.children, newPath)
];
});
}
return _.flattenDeep(recurse(tree, []));
}
This one gives you the expected answer but it's not in ideal functional style;
The idea is to start flattening the array from outside. On each iteration of the while()
loop the array is flattened by one level. Items of that level are appended to the result
and children of those items are appended to the children
array. In next iteration we flatten those children. When there are no more items in the children
array it means that we finished processing the last level. Finally we sort items by pathname
which effectively groups parents and their children together.
var current = data;
var level = 0;
var result = [];
var children = [];
while(current.length > 0) {
result = result.concat(_.map(current, function(item) {
if (!_.isArray(item.path)) {
item.path = [];
}
item.path.push(item.name);
children = children.concat(_.map(item.children, function(child) {
child.path = item.path.slice();
return child;
}));
item.level = level;
item.pathname = item.path.join(" > ");
delete item.path;
delete item.children;
return item;
}));
current = children;
children = [];
level++;
}
result.sort(function(a, b) {
return a.pathname.localeCompare(b.pathname);
});
console.log(result);
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