Search code examples
javascriptarraysalgorithmtreelodash

What is the most efficient way to transform an array of array of string to a tree objet with lodash?


I'm looking for a way to transform an array of array of string (which represents a path) into a tree like object if possible with Lodash or pure javascript if it's more efficient. I suspect we must use some recursive function inside but I'm struggling finding how to do it.

var paths = [
  ['folder1', 'folder2', 'name1.txt'],
  ['folder1', 'folder2', 'name2.txt'],
  ['folder1', 'folder3', 'name3.txt'],
  ['folder2', 'folder4', 'name4.txt'],
  ['folder2', 'folder5', 'name5.txt'],
  ['folder2', 'folder5', 'folder6', 'name6.txt'],
  ['folder3', 'name7.txt']
];

var tree = [
  {
    name: 'folder1',
    children: [
      {
        name: 'folder2',
        children: [
          {
            name: 'name1.txt'
          },
          {
            name: 'name2.txt'
          }
        ]
      },
      {
        name: 'folder3',
        children: [
          {
            name: 'name3.txt'
          }
        ]
      }
    ]
  },
  {
    name: 'folder2',
    children: [
      {
        name: 'folder4',
        children: [
          {
            name: 'name4.txt'
          }
        ]
      },
      {
        name: 'folder5',
        children: [
          {
            name: 'name5.txt'
          },
          {
            name: 'folder6',
            children: [{ name: 'name6.txt' }]
          }
        ]
      }
    ]
  },
  {
    name: 'folder3',
    children: [{ name: 'name7.txt' }]
  }
];



var pathToTree = function(paths) {
  var tree = [];
  //... ???
  return tree;
};

pathToTree(paths);


Solution

  • You could do this with forEach() and reduce() methods.

    var paths = [["folder1","folder2","name1.txt"],["folder1","folder2","name2.txt"],["folder1","folder3","name3.txt"],["folder2","folder4","name4.txt"],["folder2","folder5","name5.txt"],["folder2","folder5","folder6","name6.txt"],["folder3","name7.txt"]]
    const result = [], tmp = {result}
    
    paths.forEach(path => {
      path.reduce(function(r, name, i) {
        if(!r[name]) {
          const o = {name}, children = []
          r[name] = {result: children}
          if(path[i + 1]) o.children = children
          r.result.push(o)
        }
        return r[name]
      }, tmp)
    })
    
    console.log(result)