从绝对文件路径构建JSON对象

时间:2015-03-24 18:29:12

标签: javascript json

我从服务器收到(在我的angularjs应用程序中)这样的目录列表:

['.trash-user',
 'cats',
 'cats/css',
 'cats/images/blog',
 'cats/images/gallery']

我想构建一个如下所示的javascript变量:

[{
 label: '.trash-user'},
{label: 'cats',
 children: [{
   label: 'css'},
  {label: 'images',
   children: [{
      label: 'blog'},
     {label: 'gallery'}
     ]}
  ]}
}]

路径是随机的。

希望有人有一些非常优雅的解决方案,但任何解决方案都表示赞赏!

编辑: 这是我的天真的方法,我有递归的真正麻烦。 我只能让0级工作:

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

2 个答案:

答案 0 :(得分:4)

如果你想要一个优雅的解决方案,让我们从更优雅的输出开始:

{
  '.trash-user': {},
  'cats': {
    'css': {},
    'images': {
      'blog': {},
      'gallery': {},
    },
  },
}

对象比存储唯一键的数组要好得多,而且速度也快得多(顺序为1而不是n阶)。要获得上述输出,请执行以下操作:

var obj = {};
src.forEach(p => p.split('/').reduce((o,name) => o[name] = o[name] || {}, obj));

或在ES6之前的JavaScript:

var obj = {};
src.forEach(function(p) {
  return p.split('/').reduce(function(o,name) {
    return o[name] = o[name] || {};
  }, obj);
});

现在你有了一个自然对象树,可以很容易地映射到你想要的任何东西。要获得所需的输出,请执行以下操作:

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

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

我冒险首先生成自然树,然后转换为数组将比直接处理数组的任何算法都更好地扩展,因为查找速度更快,对象和文件树之间的自然阻抗匹配。

JSFiddles:ES6(例如Firefox),non-ES6

答案 1 :(得分:3)

这样的事情应该有效:

function pathsToObject(paths) {
    var result = [ ];

    // Iterate through the original list, spliting up each path
    // and passing it to our recursive processing function
    paths.forEach(function(path) {
        path = path.split('/');
        buildFromSegments(result, path);
    });

    return result;

    // Processes each path recursively, one segment at a time
    function buildFromSegments(scope, pathSegments) {
        // Remove the first segment from the path
        var current = pathSegments.shift();

        // See if that segment already exists in the current scope
        var found = findInScope(scope, current);

        // If we did not find a match, create the new object for
        // this path segment
        if (! found) {
            scope.push(found = {
                label: current
            });
        }

        // If there are still path segments left, we need to create
        // a children array (if we haven't already) and recurse further
        if (pathSegments.length) {
            found.children = found.children || [ ];
            buildFromSegments(found.children, pathSegments);
        }
    }

    // Attempts to find a ptah segment in the current scope
    function findInScope(scope, find) {
        for (var i = 0; i < scope.length; i++) {
            if (scope[i].label === find) {
                return scope[i];
            }
        }
    }
}