2017-06-21 121 views
5

我正在寻找将多个字符串路径转换为使用javascript的嵌套对象的最佳方法。如果可以以任何方式帮助,我正在使用lodash。从多个字符串路径创建嵌套对象

我得到了以下路径:

/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 

,我想创建对象的下列数组:在每个字符串

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": [] 
       } 
      ] 
      } 
     ] 
     } 
    ]; 

回答

6

我建议实现一个树插入函数,其参数是一个包含子元素和路径的数组。它根据给定的路径穿过的孩子,并插入必要的新的孩子,避免重复:

// 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);

+0

我想知道哪个更快,或者@Jonasw的答案。任何想法?这对我来说更可读。如果可能的话,请双击两次。 :D –

+0

@GeomanYabes这等于我的第一个答案(但它看起来好多了) –

+0

@GeomanYabes这个递归函数紧跟在生成的树结构之后,并在线性时间内搜索数组中的匹配子元素。这可以通过直接将子对象映射到父树节点的对象属性并稍后转换为OP的数组布局来加以改进。这会带来额外的不变成本,因此可能不合意,除非OP处理大量路径。 –

1

迭代并将它解析为一个对象:

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


改进版本:

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); 

它创建相同的结果,但它可能更快(最多为O(n)与O(N + N)!) http://jsbin.com/xumazinesa/edit?console

+0

'dir.children [副]'不会返回任何东西。它会查找'dir.children [“文件夹1”]等。'dir.children'是一个对象数组,而不是对象本身。您将为数组对象添加属性,如果我曾经见过一个属性,则这是一种反模式。你的输出看起来不像OP的期望输出 – mhodges

+1

看起来现在可行。如果它有一些空白,我会赞成它。 –

+0

有你去,现在看起来不错。不是条件表达式内部赋值的粉丝,但它有效。 – mhodges