Assume this below array of objects that sorted by code
property in ascii order:
var codes = [
{ code: '01' },
{ code: '0101' },
{ code: '0102' },
{ code: '010201' },
{ code: '0103' },
{ code: '02' },
{ code: '0201' },
{ code: '0202' },
];
How can I convert this to a nested array like this :
var nestedCodes = [
{
code: '01',
children: [
{ code: '0101' },
{
code: '0102',
children: [
{ code: '010201' }
]
},
{ code: '0103' }
]
},
{
code: '02',
children: [
{ code: '0201' },
{ code: '0202' }
]
}
];
The structure of codes is like concatenating multiple 0N
that N
can be a number between 1 and 9. Note that codes come from server and there would be some additional properties beside code
like title
but it doesn't matter in this problem.
The main idea here is to make an appropriate format for jsTree.
You can do this with a recursive solution. The idea is to maintain the path
(obtained as an array via String.prototype.match
with a regex) and the parent
under which you want to insert the code
for each recursive call.
The parent
keeps track of the node you want to pick in the "current" recursive call, and path
helps in building the parent
as you keep going deeper:
function insert(d, path, parent, arr) {
if (path.length === 0) {
arr.push(Object.assign({}, d));
return;
}
var target = arr.find(e => e.code === parent);
target.children = target.children || [];
insert(d, path.slice(1), parent + path[0], target.children);
}
var codes = [
{ code: '01' },
{ code: '0101' },
{ code: '0102' },
{ code: '010201' },
{ code: '0103' },
{ code: '02' },
{ code: '0201' },
{ code: '0202' },
];
var res = codes.reduce((a, c) => {
var p = c.code.match(/(0[1-9])/g);
insert(c, p.slice(1), p[0], a);
return a;
}, []);
console.log(res);
The assumption, of course, is that when a code
is being inserted, its parent has already been inserted before.