Skip to content

Build tree array from flat ordered array when only “depth” and NOT “parent ID” is known

The answers in this thread and in other places I’ve searched only work if “parent_id” is known for each object in the array.

What if the only property for the objects is depth?

The depth essentially tells me if the item is a “root node” (depth of 1) or a “child node” (depth of 2 or more).

A child’s parent is the object directly before it if the preceding object has a smaller depth. (The parent’s depth should always be 1 more than its child.)

If an object and the preceding object has the same depth, then they are actually siblings on the same level

If the preceding object has a higher depth, then the current item is actually the sibling of the earliest preceding item that has the same depth (or you could also look at it as the child of the earliest preceding item that has a lower depth)

E.g.

// Please note "name" in the example below 
// is just for illustrative purposes.
// My actual array will have random names

const items = [
    {
        name: "1",
        depth: 1,
    },
    {
        name: "2",
        depth: 1,
    },
    {
        name: "2_1",
        depth: 2,
    },
    {
        name: "2_1_1",
        depth: 3,
    },
    {
        name: "2_1_2",
        depth: 3,
    },
    {
        name: "2_2",
        depth: 2,
    },
]

So I would want to convert that flat array into a tree like:

const newItems = [
    {
        name: "1",
        depth: 1,
        children: [],
    },
    {
        name: "2",
        depth: 1,
        children: [
            {
                name: "2_1",
                depth: 2,
                children: [
                    {
                        name: "2_1_1",
                        depth: 3,
                        children: [],
                    },
                    {
                        name: "2_1_2",
                        depth: 3,
                        children: [],
                    },
                ],
            },
            {
                name: "2_2",
                depth: 2,
                children: [],
            },
        ],
    },
]

Answer

You could take a helper array for the levels and assign the object to the latest array of the depth.

const
    items = [{ name: "1", depth: 1 }, { name: "2", depth: 1 }, { name: "2_1", depth: 2 }, { name: "2_1_1", depth: 3 }, { name: "2_1_2", depth: 3 }, { name: "2_2", depth: 2 }],
    tree = [],
    levels = [tree];

items.forEach(o =>
    levels[o.depth - 1].push({ ...o, children: levels[o.depth] = [] })
);

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }