I'm looking for the best way to convert multiple string paths to a nested object with javascript. I'm using lodash if that could help in any way.
I got the following paths:
/root/library/Folder 1
/root/library/Folder 2
/root/library/Folder 1/Document.docx
/root/library/Folder 1/Document 2.docx
/root/library/Folder 2/Document 3.docx
/root/library/Document 4.docx
and I would like to create the following array of object:
var objectArray =
[
{
"name": "root", "children": [
{
"name": "library", "children": [
{
"name": "Folder 1", "children": [
{ "name": "Document.docx", "children": [] },
{ "name": "Document 2.docx", "children": [] }
]
},
{
"name": "Folder 2", "children": [
{ "name": "Document 3.docx", "children": [] }
]
},
{
"name": "Document 4.docx", "children": []
}
]
}
]
}
];
Accessing nested JavaScript objects with string key. You can use lodash's get method to get properties at any level safely. Getting first-level properties is pretty straightforward. Nested property access is tricky and you should use a tested library like lodash for it.
Each nested object must have a unique access path. The same field name can occur in nested objects in the same document. However, the full access name must still be unique. To access nested fields, concatenate the field names with a . (dot) as separator. For example, use author.lastname to access the surname for the author in this document:
Getting first-level properties is pretty straightforward. Nested property access is tricky and you should use a tested library like lodash for it. You can access a deeply nested object in the following way −
The problem with the first approach is that the output gives no idea about the nested object or the class A and its attributes, and if that is ones requirement then we are good to go.
I suggest implementing a tree insertion function whose arguments are an array of children and a path. It traverses the children according to the given path and inserts new children as necessary, avoiding duplicates:
// Insert path into directory tree structure:
function insert(children = [], [head, ...tail]) {
let child = children.find(child => child.name === head);
if (!child) children.push(child = {name: head, children: []});
if (tail.length > 0) insert(child.children, tail);
return children;
}
// Example:
let paths = [
'/root/library/Folder 1',
'/root/library/Folder 2',
'/root/library/Folder 1/Document.docx',
'/root/library/Folder 1/Document 2.docx',
'/root/library/Folder 2/Document 3.docx',
'/root/library/Document 4.docx'
];
let objectArray = paths
.map(path => path.split('/').slice(1))
.reduce((children, path) => insert(children, path), []);
console.log(objectArray);
Iterate over each string and resolve it to an object:
var glob={name:undefined,children:[]};
["/root/library/Folder 1","/root/library/Folder 2","/root/library/Folder 1/Document.docx","/root/library/Folder 1/Document 2.docx","/root/library/Folder 2/Document 3.docx","/root/library/Document 4.docx"]
.forEach(function(path){
path.split("/").slice(1).reduce(function(dir,sub){
var children;
if(children=dir.children.find(el=>el.name===sub)){
return children;
}
children={name:sub,children:[]};
dir.children.push(children);
return children;
},glob);
});
console.log(glob);
http://jsbin.com/yusopiguci/edit?console
Improved version:
var glob={name:undefined,children:[]};
var symbol="/" /* or Symbol("lookup") in modern browsers */ ;
var lookup={[symbol]:glob};
["/root/library/Folder 1","/root/library/Folder 2","/root/library/Folder 1/Document.docx","/root/library/Folder 1/Document 2.docx","/root/library/Folder 2/Document 3.docx","/root/library/Document 4.docx"]
.forEach(function(path){
path.split("/").slice(1).reduce(function(dir,sub){
if(!dir[sub]){
let subObj={name:sub,children:[]};
dir[symbol].children.push(subObj);
return dir[sub]={[symbol]:subObj};
}
return dir[sub];
},lookup);
});
console.log(glob);
It creates the same result but it is may much faster ( up to O(n) vs. O(n+n!)) http://jsbin.com/xumazinesa/edit?console
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