2017-06-21 117 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