cabef
cabef

Reputation: 5

Build a directory tree from an object

Having an array of items with the following format:

[ { path: '/Folder 1/Folder 1.1',
    name: 'Folder 1.1.1',
    id: 'Fi6CsP4RWFutOZKsIDoYMSfBPQb-A-lj3C4Jc_zZoG0' },
  { path: '/Folder 1',
    name: 'Folder 1.2',
    id: 'c2dTN3CgBr9Xik8jdpBkfzR6wZ00oGTX3IbfXrfFujM' },
  { path: '/Folder 1',
    name: 'Folder 1.1',
    id: 'WmKaOZhzpubcunNNoxbUnqfSYVuNQZDNC852KDJK_G8' },
  { path: '/',
    name: 'Folder 1',
    id: 'aNRvIvCLyNOgLOmZVzFhoOiZMAz3-p87kBFIGSQS2Yg' },
  { path: '/',
    name: 'Folder 2',
    id: 'S4FkkQ3hgLTVedIrlSBqe2_1DhrrnLx5szk7-9Wv3X8' } ]

It is possible to take it to a format like the following

var dir = {
"directory": [{
        "text": "Folder 1",
        "id": 'aNRvIvCLyNOgLOmZVzFhoOiZMAz3-p87kBFIGSQS2Yg',
        "nodes": [{
            "text": "Folder 1.1",
            "id": 'WmKaOZhzpubcunNNoxbUnqfSYVuNQZDNC852KDJK_G8',
            "nodes": [{
                "text": "Folder 1.1.1",
                "id": 'Fi6CsP4RWFutOZKsIDoYMSfBPQb-A-lj3C4Jc_zZoG0'
            }]
            }, {
            "text": "Folder 1.2",
            "id": 'c2dTN3CgBr9Xik8jdpBkfzR6wZ00oGTX3IbfXrfFujM'
        }]
    },
    {
        "text": "Folder 2",
        "id": 'S4FkkQ3hgLTVedIrlSBqe2_1DhrrnLx5szk7-9Wv3X8'
    }
]
};

Graphically Tree

I was thinking using recursion, but I still have not been able to do it.

Upvotes: 1

Views: 102

Answers (1)

ggorlen
ggorlen

Reputation: 56905

Here's a non-recursive solution that works by first building a tree, then transforming the tree into the desired structure.

The reason for the first step is due to the slowness of iterating over node arrays in linear time and assumes no order of the flat input array. Performing lookups on an object tree structure speeds up and simplifies the process, making the result tree easy to build in a single traversal.

const treeify = data => 
  data.reduce((a, e) => {
    let level = a;
    
    e.path.split("/")
      .filter(e => e)
      .forEach(dir => {
        if (!(dir in level)) {
          level[dir] = {nodes: {}};
        }

        level = level[dir].nodes;
      })
    ;
    
    if (e.name in level) {
      level[e.name] = {
        text: e.name,
        id: e.id, 
        nodes: level[e.name].nodes
      };
    }
    else {
      level[e.name] = {text: e.name, id: e.id};
    }
    
    return a;
  }, {})
;

const format = tree => {
  const result = [];
  const stack = [[result, tree]];
  
  while (stack.length) {
    const [res, curr] = stack.pop();
    
    for (const k in curr) {
      const o = {
        id: curr[k].id,
        text: curr[k].text
      };
      res.push(o);
      
      if (curr[k].nodes) {
        o.nodes = [];
        stack.push([o.nodes, curr[k].nodes]);
      }
    }
  }
  
  return {directory: result};
};

const data = [
  {
    path: '/Folder 1/Folder 1.1',
    name: 'Folder 1.1.1',
    id: 'Fi6CsP4RWFutOZKsIDoYMSfBPQb-A-lj3C4Jc_zZoG0'
  },
  {
    path: '/Folder 1',
    name: 'Folder 1.2',
    id: 'c2dTN3CgBr9Xik8jdpBkfzR6wZ00oGTX3IbfXrfFujM'
  },
  {
    path: '/Folder 1',
    name: 'Folder 1.1',
    id: 'WmKaOZhzpubcunNNoxbUnqfSYVuNQZDNC852KDJK_G8'
  },
  {
    path: '/',
    name: 'Folder 1',
    id: 'aNRvIvCLyNOgLOmZVzFhoOiZMAz3-p87kBFIGSQS2Yg'
  },
  {
    path: '/',
    name: 'Folder 2',
    id: 'S4FkkQ3hgLTVedIrlSBqe2_1DhrrnLx5szk7-9Wv3X8'
  }
];

console.log(format(treeify(data)));

Upvotes: 2

Related Questions