Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show a list or array into a tree structure in javascript?

Tags:

javascript

I pass this list from python to javascript like this:

 var string=["test_data/new_directory/ok.txt","test_data/reads_1.fq","test_data/test_ref.fa"];

I want output like this:

test_data
  reads_1.fq
  test_ref.fa
  new_directory
    ok.txt

Or also the output could be like this:

test_data
 reads_1.fq
 test_ref.fa

test_data/new_directory
  ok.txt

I used split function to get a list with each file and directory like this:

var string=["test_data/new_directory/ok.txt","test_data/reads_1.fq","test_data/test_ref.fa"];

                                     for(var i=0;i<string.length;i++){

                                         var result = string[i].split('/');

                                          console.log(result);


                                     }

Output looks like this:

["test_data", "new_directory", "ok.txt"]
["test_data", "reads_1.fq"]
["test_data", "test_ref.fa"]

How can I convert into the format I showed above? Thanks

like image 791
pynovice Avatar asked Jun 17 '13 05:06

pynovice


2 Answers

Sorry for being late to the party. I ran into a similar issue trying to break out a list of paths into a nested object. Here's a fiddle showing how I ended up doing it.

var list = [];
list.push("A/B/C");
list.push("A/B/D");
list.push("A/B/C");
list.push("B/D/E");
list.push("D/B/E");
list.push("A/D/C");

var data = [];
for(var i = 0 ; i< list.length; i++)
{
   buildTree(list[i].split('/'),data);    
}
debugger;

function buildTree(parts,treeNode) {
     if(parts.length === 0)
     {
          return; 
     }

     for(var i = 0 ; i < treeNode.length; i++)
     {
          if(parts[0] == treeNode[i].text)
          {
              buildTree(parts.splice(1,parts.length),treeNode[i].children);
              return;
          }
     }

     var newNode = {'text': parts[0] ,'children':[]};
     treeNode.push(newNode);
     buildTree(parts.splice(1,parts.length),newNode.children);
}

https://jsfiddle.net/z07q8omt/

like image 77
neonScarecrow Avatar answered Oct 02 '22 19:10

neonScarecrow


That's certainly possible, but it requires recursion.

The first thing you'll want to do (as you've already figured out to do, in fact) is split on the slashes. We'll use map for simplicity:

paths = paths.map(function(path) { return path.split('/'); });

Now we'll want to convert this into an array of objects with name and children properties. This means we'll have to use recursion.

In this function, we'll do a first pass grouping them by their first element:

var items = [];
for(var i = 0, l = paths.length; i < l; i++) {
    var path = paths[i];
    var name = path[0];
    var rest = path.slice(1);
    var item = null;
    for(var j = 0, m = items.length; j < m; j++) {
        if(items[j].name === name) {
            item = items[j];
            break;
        }
    }
    if(item === null) {
        item = {name: name, children: []};
        items.push(item);
    }
    if(rest.length > 0) {
        item.children.push(rest);
    }
}

Then we can recurse on all of these (assuming the function name we chose was structurize):

for(i = 0, l = items.length; i < l; i++) {
    item = items[i];
    item.children = structurize(item.children);
}

Now we've got a nice structure. We can then stringify it, again with a recursive function. Since the directory listing is just each item name followed by the indented directory contents listing, we can write that fairly easily:

function stringify(items) {
    var lines = [];
    for(var i = 0, l = items.length; i < l; i++) {
        var item = items[i];
        lines.push(item.name);
        var subLines = stringify(item.children);
        for(var j = 0, m = subLines.length; j < m; j++) {
            lines.push("  " + subLines[j]);
        }
    }
    return lines;
}

Then, to actually do it:

console.log(stringify(structurize(paths)).join("\n"));
like image 32
icktoofay Avatar answered Oct 02 '22 19:10

icktoofay