Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array of path-name strings to treeview

I have input data like:

['Level 1/Level 2/Level 3/ Level4a',
'Level 1/Level 2/Level 3/ Level4b',
'Level 1/Level 2/Level 3/ Level4c',
'Level 1/Level 2/Level 3/ Level4a',
'Level 1c/Level 2d/Level 3b/ Level4d',
'Level 1c/Level 2d/Level 3b/ Level4e',
'Level 1c/Level 2d/Level 3b/ Level4f']

Now I would like to convert it to treeview array like this:

tree: [
                {
                    name: 'Level 1',
                    children: [
                        {
                            name: 'Level 2',
                            children: [
                                {
                                    name: 'Level 3',
                                    children: [
                                        {name: 'Level 4a'},
                                        {name: 'Level 4b'},
                                        {name: 'Level 4c'}
                                    ]
                                }
                            ]
                        }
                    ]
                },
                {
                    name: 'Level 1c',
                    children: [
                        {
                            name: 'Level 2d',
                            children: [
                                {
                                    name: 'Level 3b',
                                    children: [
                                        {name: 'Level 4d'},
                                        {name: 'Level 4e'},
                                        {name: 'Level 4f'}
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]

There is a way to iterate, but its to much complex, I guess. What is the best optimal way to do this?

like image 288
ulou Avatar asked Dec 06 '25 22:12

ulou


2 Answers

You could take an array of the last inserted objects and check if the name is not equal to the last one. if so, add a new object.

var data = ['Level 1/Level 2/Level 3/Level4a', 'Level 1/Level 2/Level 3/Level4b', 'Level 1/Level 2/Level 3/Level4c', 'Level 1/Level 2/Level 3/Level4a', 'Level 1c/Level 2d/Level 3b/Level4d', 'Level 1c/Level 2d/Level 3b/Level4e', 'Level 1c/Level 2d/Level 3b/Level4f'],
    tree = [],
    levels = [{ children: tree }];

data.forEach(s => s.split('/').forEach((name, i) => {
    if (!levels[i + 1] || levels[i + 1].name !== name) {
        levels[i].children = levels[i].children || [];
        levels[i].children.push(levels[i + 1] = { name });
    }
}));

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 91
Nina Scholz Avatar answered Dec 08 '25 12:12

Nina Scholz


You can use 2 reduces. The first one is to loop thru the array. The second reduce is to loop thru the split() string. Use find() to check an element exist on an array

var arr = ['Level 1/Level 2/Level 3/ Level4a', 'Level 1/Level 2/Level 3/ Level4b', 'Level 1/Level 2/Level 3/ Level4c', 'Level 1/Level 2/Level 3/ Level4a', 'Level 1c/Level 2/Level 3/ Level4d', 'Level 1c/Level 2/Level 3/ Level4e', 'Level 1c/Level 2/Level 3/ Level4f'];

var result = arr.reduce((c, v) => {
  v.split('/').reduce((a, o, i) => {
    if (i === 0) var p = a;
    else var p = a.children = a.children || [];

    let f = p.find(x => x.name === o.trim());
    if (!f) {
      f = {name: o.trim()};
      p.push(f);
    }

    return f;
  }, c);

  return c;
}, []);


console.log(result);
like image 36
Eddie Avatar answered Dec 08 '25 10:12

Eddie