-2

I have an array as follow

arr = [
    {
        id: 1,
        name: 'Node1',
        level: 1
    },
    {
        id: 2,
        name: 'Node2',
        level: 2
    },
    {
        id: 3,
        name: 'Node3',
        level: 3
    },
    {
        id: 4,
        name: 'Node4',
        level: 4
    },
    {
        id: 5,
        name: 'Node5',
        level: 5
    },
];

I want to generate tree on basis of level. Output should be

tree = 
{
    id: 1,
    name: 'Node1',
    level: 1,
    nodes: {
        id: 2,
        name: 'Node2',
        level: 2,
        nodes : {
            id: 3,
            name: 'Node3',
            level: 3,
            nodes: {
                id: 4,
                name: 'Node4',
                level: 4,
                nodes : {
                    id: 5,
                    name: 'Node5',
                    level: 5,
                    nodes: []
                }
            }
        }
    }
}

whenever nodes = [], that means it's the last nodes. the order of array can be anything but tree should be built on basis of level.

Khilen Maniyar
  • 2,519
  • 7
  • 31
  • 35
  • Is there a question here? – charlietfl Jun 13 '17 at 09:34
  • Possible Dup of [Build tree array from flat array in javascript](//stackoverflow.com/q/18017869), [Construct hierarchy tree from flat list with parent field?](//stackoverflow.com/q/22367711), [Convert parent-child array to tree](//stackoverflow.com/q/15792794) and here's algorithm [How to efficiently build a tree from a flat structure?](//stackoverflow.com/q/444296) – Tushar Jun 13 '17 at 09:35
  • @Tushar, actually not because the given structure reflects only the level, but not the parent, which is different from the dupe targets. – Nina Scholz Jun 13 '17 at 11:12

2 Answers2

8

You could use the level property for indicating the nested position in a helper array. Then iterate the data and build children nodes if necessary.

function getTree(array) {
    var levels = [{}];
    array.forEach(function (a) {
        levels.length = a.level;
        levels[a.level - 1].nodes = levels[a.level - 1].nodes || [];
        levels[a.level - 1].nodes.push(a);
        levels[a.level] = a;
    });
    return levels[0].nodes;
}

console.log(getTree([{ id: 1, name: 'Node1', level: 1 }, { id: 2, name: 'Node2', level: 2 }, { id: 3, name: 'Node3', level: 3 }, { id: 4, name: 'Node4', level: 4 }, { id: 5, name: 'Node5', level: 5 }]));
console.log(getTree([{ id: 1, name: 'Node 1', level: 1 }, { id: 2, name: 'Node 1.1', level: 2 }, { id: 3, name: 'Node 1.1.1', level: 3 }, { id: 4, name: 'Node 1.1.1.1', level: 4 }, { id: 5, name: 'Node 1.2', level: 2 }, { id: 6, name: 'Node 1.2.1', level: 3 }, ]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Interpreting the `level` property not as a parental relationship but only an indication of the level, would require to insert the same object under all objects at the same level. But your code does not do that. Check with the input `[{ id: 1, name: 'Node1', level: 1 }, { id: 2.1, name: 'Node2.1', level: 2 }, { id: 2.2, name: 'Node2.2', level: 2 }, { id: 3, name: 'Node3', level: 3 }, { id: 4, name: 'Node4', level: 4 }]`. The objects with id 3 and it's children should be inserted under all objects at level 2, not only the last one. – Redu Jun 13 '17 at 12:54
  • @redu, that is an assumption without reference. as i interpret the question all item follows the last level, otherwise a tree would impossible to build. – Nina Scholz Jun 13 '17 at 13:09
  • I agree that the OP's data structure is not a conventional one with solid one to one parental relationship, which actually makes the question a separate one to the ones mentioned in @Tushar's comment. Yet I don't understand why it would be impossible to built a a tree by level information instead of parent..? Actually, thanks to you "nesting the flat data by referencing" technique is something i have picked up from one of your earlier answers. Let me try if i can do it... – Redu Jun 13 '17 at 13:20
  • It is just a one level.. Is it possible to build with multiple children for the same level and multiple level also? – Balaji Perumal Aug 29 '17 at 18:19
  • @BalajiPerumal, it is possible with a different algorithm and data with a parent or children property. – Nina Scholz Aug 29 '17 at 18:27
  • I have the same same structure as this one.. There is no parent child relation. I have to build the structure with level fluctuations.. Can you direct me to the right way? – Balaji Perumal Aug 29 '17 at 18:29
  • @BalajiPerumal, please ask a question with the data and your try. – Nina Scholz Aug 29 '17 at 18:33
  • The data would be like this, 1, 2.1, 2.2,... 2.10, 3, 3.1.. 3.8, 2.11, 2.12, 4, 2.13 so on. structure is exactly same as above.. only level.. no parent ids – Balaji Perumal Aug 29 '17 at 18:34
  • but the number reflects the same level and nesting. – Nina Scholz Aug 29 '17 at 18:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/153161/discussion-between-balaji-perumal-and-nina-scholz). – Balaji Perumal Aug 29 '17 at 18:36
0

Well, as per our mutual commenting under @Nina Scholz's answer I believe this is an interesting question. We will have to create a nested structure not depending on the parental relationship among the objects but the level relationship among each object and the tree structure. Which means an object with level property as n should be present under all branches with at least n-1 levels.

So thanks to objects being reference types, as in parental relationship, we can still do this job with O(n) time complexity by using a single .reduce().

Here is my approach;

var data = [{ id: 1, name: 'Node1', level: 1 }, { id: 2.1, name: 'Node2.1', level: 2 }, { id: 2.2, name: 'Node2.2', level: 2 }, { id: 3.1, name: 'Node3.1', level: 3 }, { id: 3.2, name: 'Node3.2', level: 3 }, { id: 4, name: 'Node4', level: 4 }],
    tree = data.reduce(function(r,o,i){
                         r.prt = o.level-1;
                         r[r.prt] ? r[r.prt][0].children.push(o)
                                  : r[r.prt] = [{id: 0, name: "Root", level: r.prt, children: [o]}];
                         r[o.level] = r[o.level] ? (o.children = r[o.level][0].children,
                                                    r[o.level][0].id === 0 ? r[o.level][0] = o
                                                                           : r[o.level].push(o),
                                                    r[o.level])
                                                 : [Object.assign(o, {children: []})];
                         return r;
                       }, {prt: void 0});
console.log(JSON.stringify(tree[0],null,4));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Redu
  • 25,060
  • 6
  • 56
  • 76
  • you have dupes ... from 3.1 on – Nina Scholz Jun 13 '17 at 15:30
  • @Nina Scholz Well.. that's the point. Since 3.1 and 3.2 are listed as level 3 objects, they are placed under all level 2 objects (in this case 2.1 and 2.2) along with their children. In other words their parents are all level 2 objects. – Redu Jun 13 '17 at 15:39
  • maybe you have a look to my answer for the second, there the position in the array defines the use of the parent object. – Nina Scholz Jun 13 '17 at 15:44
  • @Nina Scholz Yes i went through your answer but you and i have different interpretations of the question. I am going for all parents at the previous level while you prefer to pick a single parent from the previous level (which is the last one) I shouldn't say you are doing wrong but i guess my approach makes this question unique, if i may say so. Actually i liked this question very much. – Redu Jun 13 '17 at 15:51
  • It is just a one level.. Is it possible to build with multiple children for the same level and multiple level also? – Balaji Perumal Aug 29 '17 at 18:20
  • For example, 1, 2.1, 2.2,... 2.10, 3, 3.1.. 3.8, 2.11, 2.12, 4, 2.. so on..? structure is exactly same as above.. only level.. no parent ids – Balaji Perumal Aug 29 '17 at 18:27
  • @Balaji Perumal Yes.. the above snippet already has two separate objects at level 2 (could be indefinitely many) and "all" level 3 and below items are listed under "both" level 2 objects according to their hierarchy with this approach. That's probably the main difference between the accepted solution and this one. – Redu Aug 29 '17 at 19:09