javascriptjsonreactjstreefiletree

Array of filepath strings to file tree JSON (compatible with react-sortable-tree)


How do I build a JSON object thats is compatible with react-sortable-tree (every nested object has title, children) to render the file tree.

For example, I have this array of filepaths.

var filePaths = [
   "Diagnoses/Endocrine disorders/Thyroid disorders/Congenital hypothyroidism",
   "Diagnoses/Endocrine disorders/Thyroid disorders/Acquired hypothyroidism",
   "Diagnoses/Endocrine disorders/Thyroid disorders/Acquired hypothyroidism/Postsurgical hypothyroidism"
];

I would like a JSON Object like this.

var treeData = [
  {
    title: 'Diagnoses',
    children: [{
      title: 'Endocrine disorders',
      children: [{
        title: 'Thyroid disorders',
        children: [
        {
          title: 'Congential hypothyroidism'
        },
        {
          title: 'Acquired hypothyroidism',
          children: [{
            title: 'Postsurgical hypothyroidism'
          }]
        }
        ]
      }]
    }]
  }
];

Edit: I tried this but after the first iteration, I'm overwriting the children property of the whole tree. I tried a couple of checks to stop that but they didn't quite pan out.

var hierarchy = filePaths.reduce(function(hier,path){
    var x = hier;
    path.split('/').forEach(function(item, index, array){
        if(x[0].title != item){
            x[0].title = item;
        }
        // console.log(index, array.length)
        if (index != array.length - 1 && !x[0].children){
          x[0].children = [{
            title: ''
          }];
        }
        x = x[0].children;
    });

    return hier;
}, [{title: ''}]);

Solution

  • I think the main issue with your code is that you're not walking down the tree to insert nodes at the right place.

    I took a two-step approach, since I didn't like the idea of iterating through a list of children each time when a dictionary lookup would be faster.

    See the comments in the code for an explanation of what's going on:

    var filePaths = [
      "Diagnoses/Endocrine disorders/Thyroid disorders/Congenital hypothyroidism",
      "Diagnoses/Endocrine disorders/Thyroid disorders/Acquired hypothyroidism",
      "Diagnoses/Endocrine disorders/Thyroid disorders/Acquired hypothyroidism/Postsurgical hypothyroidism"
    ];
    
    // Step 1:
    // Convert the flat list of paths to nested dictionaries.
    // (This representation is more efficient for the initial construction.)
    // Basic algorithm:
    // 1. Split each path into segments.
    // 2. Walk down the tree using the segments as keys.
    // 3. Create new nodes as necessary.
    
    var tree = {};
    filePaths.forEach(function (path) {
      var currentNode = tree;
      path.split('/').forEach(function (segment) {
        if (currentNode[segment] === undefined) {
          currentNode[segment] = {};
        }
        currentNode = currentNode[segment];
      });
    });
    
    // Now we have a tree represented as nested dictionaries.
    console.log(JSON.stringify(tree, null, 2));
    
    // {
    //   "Diagnoses": {
    //     "Endocrine disorders": {
    //       "Thyroid disorders": {
    //         "Congenital hypothyroidism": {},
    //         "Acquired hypothyroidism": {
    //           "Postsurgical hypothyroidism": {}
    //         }
    //       }
    //     }
    //   }
    // }
    
    // Step 2:
    // Convert the nested dictionaries into lists of children.
    // This is the format required for react-sortable-tree.
    // Basic algorithm:
    // 1. Each dictionary becomes an array of children.
    // 2. Each element of the array has a title and a list of children.
    // 3. We recurse for the list of children (if we have children).
    function toTreeData(tree) {
      return Object.keys(tree).map(function (title) {
        var o = { title: title };
        if (Object.keys(tree[title]).length > 0) {
          o.children = toTreeData(tree[title]);
        }
    
        return o;
      });
    }
    
    console.log(JSON.stringify(toTreeData(tree), null, 2));
    
    // [
    //   {
    //     "title": "Diagnoses",
    //     "children": [
    //       {
    //         "title": "Endocrine disorders",
    //         "children": [
    //           {
    //             "title": "Thyroid disorders",
    //             "children": [
    //               {
    //                 "title": "Congenital hypothyroidism"
    //               },
    //               {
    //                 "title": "Acquired hypothyroidism",
    //                 "children": [
    //                   {
    //                     "title": "Postsurgical hypothyroidism"
    //                   }
    //                 ]
    //               }
    //             ]
    //           }
    //         ]
    //       }
    //     ]
    //   }
    // ]