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: [], }, ], }, ]
Advertisement
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; }