Reputation: 1009
I've been struggling to find a solution for this for a few hours. I've made some attempts and scratched them, my closest attempt is at the end of this question..
Assume I wish to build a table of contents using h1
...h6
tags, I don't have any nesting using divs, etc. The tag is what informs the table of contents if it is a parent or child.
For example, a h1
then a h2
means the h2
is a child of the h1
.
Lets assume we have an array of elements:
// omitting other properties like 'text', etc for brevity.
[{ tag: 2 }, { tag: 2 }, { tag: 3 }, { tag: 3 }, { tag: 4 }, { tag: 2 }]
This would represent the following HTML:
<div>
<h2>
<h2>
<h3>
<h3>
<h4>
<h2>
</div>
And we are after a tree that looks like this:
[{
tag: 2
}, {
tag: 2
children: [{
tag: 3
}, {
tag: 3,
children: [{
tag: 4
}]
}]
}, {
tag: 2
}]
It shouldn't be too difficult, but I just can't wrap my head around it. Instead of a parent reference (as most other questions have), I am strictly using the number value to signify if its a parent.
Here's the code I've come up with that works but only in very limited circumstances. For example, if there is a sibling after the last element, it doesn't work.
Thank you!
//Loop through the array backwards
let newArr = [];
let tempArr = [];
while (arr.length) {
if (arr.length === 1) {
newArr.unshift(arr.pop())
} else {
let item = arr.pop();
if (tempArr.length == 0) {
tempArr.push(item);
item = arr.pop();
}
//Check if the items tag is equal to the tempArrs last item tag
if (item.tag == tempArr[tempArr.length - 1].tag) {
tempArr.push(item)
} else if (item.tag < tempArr[tempArr.length - 1].tag) {
item.children = tempArr;
//there might be something in newArr...
if (newArr.length && newArr[0].tag > item.tag) {
item.children.push(newArr.pop());
}
newArr.unshift(item)
tempArr = [];
}
}
}
Upvotes: 1
Views: 334
Reputation: 386522
You could use a helper array for the levels and take an offset for starting tag (assuming no smaller/parent tags are available).
var array = [{ tag: 2 }, { tag: 2 }, { tag: 3 }, { tag: 3 }, { tag: 4 }, { tag: 2 }],
offset = -array[0].tag;
result = [],
levels = [{ children: result }];
array.forEach(function (o) {
levels[o.tag + offset].children = levels[o.tag + offset].children || [];
levels[o.tag + offset].children.push(levels[o.tag + offset + 1] = o);
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1