javascript - Convert an array of objects into a nested array of objects based on string property? -
i stuck on problem trying convert flat array of objects nested array of objects based name property.
what best way convert input
array resemble structure of desiredoutput
array?
var input = [ { name: 'foo', url: '/somewhere1', templateurl: 'foo.tpl.html', title: 'title a', subtitle: 'description a' }, { name: 'foo.bar', url: '/somewhere2', templateurl: 'anotherpage.tpl.html', title: 'title b', subtitle: 'description b' }, { name: 'buzz.fizz', url: '/another/place', templateurl: 'hello.tpl.html', title: 'title c', subtitle: 'description c' }, { name: 'foo.hello.world', url: '/', templateurl: 'world.tpl.html', title: 'title d', subtitle: 'description d' } ] var desiredoutput = [ { name: 'foo', url: '/somewhere1', templateurl: 'foo.tpl.html', data: { title: 'title a', subtitle: 'description a' }, children: [ { name: 'bar', url: '/somewhere2', templateurl: 'anotherpage.tpl.html', data: { title: 'title b', subtitle: 'description b' } }, { name: 'hello', data: {}, children: [ { name: 'world', url: '/', templateurl: 'world.tpl.html', data: { title: 'title d', subtitle: 'description d' } } ] } ] }, { name: 'buzz', data: {}, children: [ { name: 'fizz', url: '/', templateurl: 'world.tpl.html', data: { title: 'title c', subtitle: 'description c' } } ] } ]
note order of objects in input array not guaranteed. code running in node.js environment , open using libraries such lodash achieve desired output.
any appreciated.
using lodash (because why on earth want manipulate complex data without utility library). here's the fiddle.
function formatroute(route) { return _.merge(_.pick(route, ['url', 'templateurl']), { name: route.name.split('.'), data: _.pick(route, ['title', 'subtitle']), children: [] }); } function getnamelength(route) { return route.name.length; } function buildtree(tree, route) { var path = _.slice(route.name, 0, -1); insertatpath(tree, path, _.merge({}, route, { name: _.last(route.name) })); return tree; } function insertatpath(children, path, route) { var head = _.first(path); var match = _.find(children, function (child) { return child.name === head; }); if (path.length === 0) { children.push(route); } else { if (!match) { match = { name: head, data: {}, children: [] }; children.push(match); } insertatpath(match.children, _.rest(path), route); } } // map routes correct formats. var routes = _.sortby(_.map(input, formatroute), getnamelength); // can reduce formatted array desired format. var out = _.reduce(routes, buildtree, []);
it works reshaping initial input split names arrays , add data / children properties. reduces data on buildtree
uses mutating function ( :( ) insert current item in reduce @ given path.
the strange if (!match)
part makes sure missing segments added in if they're not explicitly specified in initial data set url etc.
the last 2 lines work should in little function, , jsdoc. it's shame didn't recursive, i'm relying on array mutation insert route object deep within tree.
should simple enough follow though.
Comments
Post a Comment