I'm trying to take a flat array of paths, and create nested array of objects. The trouble i'm having is with the recursive part of generating children nodes...
Starting array:
const paths = [
'/',
'/blog',
'/blog/filename',
'/blog/slug',
'/blog/title',
'/website',
'/website/deploy',
'/website/infrastructure',
'/website/infrastructure/aws-notes',
];
With a desired output structure:
[
{
path: '/',
},
{
path: '/blog',
children: [
{
path: '/blog/filename',
},
{
path: '/blog/slug',
},
{
path: '/blog/title',
}
]
},
{
path: '/website',
children: [
{
path: '/website/deploy',
},
{
path: '/website/infrastructure',
children: [
{
path: '/website/infrastructure/aws-notes',
}
],
},
],
},
]
Here's where i'm at so far, i've tried a few things but ultimately ends in infinite loops or poor structure:
const getPathParts = (path) => path.substring(1).split('/');
const getPathLevel = (path) => getPathParts(path).length - 1;
const getTree = (paths) => paths.reduce((tree, path, i, paths) => {
const pathParts = getPathParts(path);
const pathDepth = getPathLevel(path);
const current = pathParts[pathDepth];
const parent = pathParts[pathDepth - 1] || null;
const item = {
path,
children: [],
};
if (pathDepth > 0 || parent !== null) {
// recursive check for parent, push this as a child to that parent?
return [...tree];
}
return [
...tree,
item,
];
}, []);
I've tried array.find|some|filter to retrieve the parent, but i'm at a loss how to push the node as a child into the correct nested node. NOTE: i've extracted some code for the example, pardon any syntax/spelling issues.
1 Answer 1
You could take a nested approach by taking the pathes and split them and check if the object with the path already exists or not. If not push a new object.
Later return the children of the actual object. Proceeed until no more path items are available.
const
paths = ['/', '/blog', '/blog/filename', '/blog/slug', '/blog/title', '/website', '/website/deploy', '/website/infrastructure', '/website/infrastructure/aws-notes'],
result = paths.reduce((r, path) => {
path.split(/(?=\/)/).reduce((a, _, i, p) => {
var temp = a.find(o => o.path === p.slice(0, i + 1).join(''));
if (!temp) {
a.push(temp = { path, children: [] });
}
return temp.children;
}, r);
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For creating by using only pathes to final directories, you could take parts of the path for creating.
This approach prevents empty children arrays.
const
paths = [
'/',
'/blog/filename',
'/blog/slug',
'/blog/title',
'/website/deploy',
'/website/infrastructure/aws-notes'
],
result = [];
paths.reduce((r, string) => {
string.split(/(?=\/)/).reduce((o, _, i, p) => {
o.children = o.children || [];
var path = p.slice(0, i + 1).join(''),
temp = o.children.find(o => o.path === path);
if (!temp) {
o.children.push(temp = { path });
}
return temp;
}, r);
return r;
}, { children: result });
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
1 Comment
Explore related questions
See similar questions with these tags.