简体   繁体   中英

Javascript multidimentional array to single object

I'm having a hard time writing an algorithm. The context is the following : I'm having an array of paths that I want to put in a single object, like rebuilding a tree of files.

Here's a simple sample :

var paths = [  
  '/var/log/log.txt',  
  '/var/log/test.txt',  
  '/home/toto/someFile.txt',
  '/wtf.txt'  
];

And I'd like this array of paths to be an object like :

var tree = {  
  var: {
    log: ['log.txt', 'test.txt']
  },
  home: {
    toto: ['someFile.txt']
  },
  wtf.txt: null // I don't know how to handle this case
};

Any hint on how to do such a thing ?

Actually, I've something like this but it ends up with a single depth level and not handling file on root level :

function rebuildTree(paths, tree) {
  paths.forEach(function (path) {
      var splittedPath;
      if (path.indexOf("/") > -1) {
          splittedPath = path.split('/');
      } else {
          splittedPath = [path];
      }

      splittedPath.some(function(item, index) {
          if (!tree.hasOwnProperty(item) && index > 0) {
              tree[item] = {};
          }

          if ((parseInt(index) + 1) <= (splittedPath.length - 1)) {
              var nextIndex = parseInt(index + 1);
              var nextPath = splittedPath.splice(0, index);
              tree[item] = rebuildTree(nextPath, tree[item]);
          }
      });
  });
} 

I have written a little helper function below that should make it easy to do, check the comments to see how it works (see your console for the output).

 function treeify(paths){ // This will store our tree var tree = {}; // This will run through all our paths paths.forEach(function(path){ // This will remove the initial slash if(path.indexOf('/') === 0) path = path.substring(1); // Find all the individual files/folders path = path.split('/'); // If there is only one we'll assume its a file and assign your `null` if(path.length === 1){ tree[path[0]] = tree[path[0]] || null; return; } // Create a variable that will store the current branch we are in var branch = tree[path[0]] = tree[path[0]] || {}; // Loop through the remaining values, repointing the branch as we go. for(var i = 1; i < path.length; i++){ // The second to last item will need to be an array (as suggested). if(i === path.length-2) branch = branch[path[i]] = branch[path[i]] || []; // The last item will be pushed to the array (as suggested). else if(i === path.length-1) branch.push(path[i]); // All others will simply create a new branch. else branch = branch[path[i]] = branch[path[i]] || {}; } }); return tree; } console.log(treeify([ '/var/log/log.txt', '/var/log/test.txt', '/home/toto/someFile.txt', '/wtf.txt' ])); 

The big downside to this is that it breaks because of the structure you want to have. A better solution would be something like the following, which reduces complexity and makes it easier to understand:

 function treeify(paths){ var tree = {}; paths.forEach(function(path){ if(path.indexOf('/') === 0) path = path.substring(1); path = path.split('/'); var branch = tree[path[0]] = tree[path[0]] || {}; for(var i = 1; i < path.length; i++){ branch = branch[path[i]] = branch[path[i]] || {}; } }); return tree; } console.log(treeify([ '/var/log/log.txt', '/var/log/test.txt', '/home/toto/someFile.txt', '/wtf.txt' ])); 

In this snippet all paths are just nested keys, and you could use the for..in construct to find something. It's less convenient, but ending in an array could cause the following issue: when you have two paths, one being a/b/c.txt and the other being a/b/c/d , the push will break and the array will fail. This means you can only have one level of depth, while this function can have any level of depths.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM