【问题标题】:Create nested object from multiple string paths从多个字符串路径创建嵌套对象
【发布时间】:2019-04-04 07:16:11
【问题描述】:

我正在寻找使用 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": []
              }
            ]
          }
        ]
      }
    ];

【问题讨论】:

    标签: javascript


    【解决方案1】:

    我建议实现一个树插入函数,其参数是子数组和路径。它根据给定的路径遍历孩子,并根据需要插入新的孩子,避免重复:

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

    【讨论】:

    • 我想知道哪个更快,这个或@Jonasw 的答案。任何想法?不过,这对我来说更具可读性。如果可能的话,会上升两次。 :D
    • @GeomanYabes 这等于我的第一个答案(但看起来好多了)
    • @GeomanYabes 这个递归函数严格遵循生成的树结构,并在线性时间内搜索数组中的匹配子项。这可以通过直接将子名称映射到父树节点的对象属性并稍后转换为 OP 的数组布局来改进。这会带来额外的恒定成本,因此除非 OP 处理大量路径,否则可能不受欢迎。
    • 哦..我明白了..只是将您的“改进”答案作为您的答案。
    • 谢谢@le_m!很好的解决方案。由于项目要求,我可能会选择 es5 方法,但我会将其标记为答案以供将来参考。
    【解决方案2】:

    遍历每个字符串并将其解析为一个对象:

    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

    【讨论】:

    • dir.children[sub] 不会返回任何内容。它将寻找dir.children["Folder 1"] 等。dir.children 是一个对象数组,而不是对象本身。您将为数组对象添加属性,如果我见过的话,这是一种反模式。你的输出看起来不像 OP 想要的输出
    • 现在看起来可以了。如果它有一些空格,我会赞成它。
    • 好了,现在看起来不错。不喜欢条件表达式中的赋值,但它确实有效。
    • 如果有一个不同根的字符串会失败,比如"/path/library/Folder 1",
    • @AvraamMavridis 是的,它不处理多个根结构,也不处理动态深度
    猜你喜欢
    • 1970-01-01
    • 2014-05-09
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多