I receive (in my angularjs application) from a server a list of directories like this:
['.trash-user',
 'cats',
 'cats/css',
 'cats/images/blog',
 'cats/images/gallery']
And I would like to build a javascript variable which looks like this:
[{
 label: '.trash-user'},
{label: 'cats',
 children: [{
   label: 'css'},
  {label: 'images',
   children: [{
      label: 'blog'},
     {label: 'gallery'}
     ]}
  ]}
}]
The paths are in random order.
Hope somebody has some really elegant solution, but any solution is appreciated!
Edit: Here is my naive approach, I have real trouble with recursion. I could only make level 0 to work:
var generateTree = function(filetree){
  console.log('--------- filetree -------');
  var model = [];
  var paths = [];
  for(var i=0;i<filetree.length;i++) {
    paths = filetree[i].split('/');
    for(var j=0;j<paths.length;++j) {
      var property = false;
      for(var k=0;k<model.length;++k) {
        if (model[k].hasOwnProperty('label') &&
            model[k].label === paths[0]) {
          property = true;
        }
      }
      if (!property) {
        model.push({label: paths[0]});
      }
    }
  }
  console.log(model);
};
                If you want an elegant solution, lets start with a more elegant output:
{
  '.trash-user': {},
  'cats': {
    'css': {},
    'images': {
      'blog': {},
      'gallery': {},
    },
  },
}
Objects are much better than arrays for storing unique keys and much faster too (order 1 instead of order n). To get the above output, do:
var obj = {};
src.forEach(p => p.split('/').reduce((o,name) => o[name] = o[name] || {}, obj));
or in pre-ES6 JavaScript:
var obj = {};
src.forEach(function(p) {
  return p.split('/').reduce(function(o,name) {
    return o[name] = o[name] || {};
  }, obj);
});
Now you have a natural object tree which can easily be mapped to anything you want. For your desired output, do:
var convert = obj => Object.keys(obj).map(key => Object.keys(obj[key]).length?
  { label: key, children: convert(obj[key]) } : { label: key });
var arr = convert(obj);
or in pre-ES6 JavaScript:
function convert(obj) {
  return Object.keys(obj).map(function(key) {
    return Object.keys(obj[key]).length?
      { label: key, children: convert(obj[key])} : { label: key };
  });
}
var arr = convert(obj);
I'll venture that generating the natural tree first and then converting to the array will scale better than any algorithm working on arrays directly, because of the faster look-up and the natural impedance match between objects and file trees.
JSFiddles: ES6 (e.g. Firefox), non-ES6.
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