How to convert an array of URLs into a tree/folder structure data?

Viewed 259

For start I have an array of URLs which I have crawled using a simple-crawler library.

The data received is what I want to transform into a tree structure or folder structure. I am using react-tabulator here because I wanted to resize columns of table. Now along with normal table, I want to have the nested folder view structure.

//input data
const urls = [
   { id: 1, address: 'https://happy.com' },
   { id: 2, address: 'https://happy.com/about' },
   { id: 3, address: 'https://happy.com/contact' },
   { id: 4, address: 'https://happy.com/contact/office' },
   { id: 5, address: 'https://happy.com/contact/home' },
   { id: 6, address: 'https://happy.com/projects' },
];

//output data
tableDataNested = [
  { id: 1, address: 'https://happy.com', 
    _children:[
      { id: 2, address: 'https://happy.com/about', _children:[] },
      { id: 3, address: 'https://happy.com/contact',
        _children:[
          { id: 4, address: 'https://happy.com/contact/office', _children:[] },
          { id: 5, address: 'https://happy.com/contact/home', _children:[] },
        ] 
      },
      { id: 6, address: 'https://happy.com/projects', _children:[] },
    ] 
  } 
];

Though I saw 1-2 posts resembling this concept, I wasn’t sure on the pure JS way of doing or probably use some nice libraries too. Any insights anyone?

2 Answers

You can just split the URL-s along the last slash (there always will be one here because of the //: part) and use a Map to track containment relations:

const urls = [
   { id: 1, address: 'https://happy.com' },
   { id: 2, address: 'https://happy.com/about' },
   { id: 3, address: 'https://happy.com/contact' },
   { id: 4, address: 'https://happy.com/contact/office' },
   { id: 5, address: 'https://happy.com/contact/home' },
   { id: 6, address: 'https://happy.com/projects' },
];

const tableDataNested = [];
const prefixmap = new Map();
for(let url of urls) {
   url._children = [];                        // extend node with the array
   let address = url.address;
   let lastslash = address.lastIndexOf('/');
   let prefix = address.substring(0,lastslash);
   if(prefixmap.has(prefix)) {                // has parent, so add to that one
      prefixmap.get(prefix)._children.push(url)
   } else {                                   // toplevel node
      tableDataNested.push(url);
   }
   prefixmap.set(address,url);                // store as potential parent in any case
}
console.log(tableDataNested);

This snippet actually modifies the original objects (in urls), but of course it's also possible to make a copy if needed, something like

url = {id:url.id,address:url.address,_children:[]};

instead of url._children = [];

Before I answer this question, I must give a fair warning that this question is broad and moderators usually flag them.

Luckily, the solution that you're looking for is alsocalled a "tree" in UI design terminologies. I found a few:

Hope, this helps.

Related