I'm using a table component from a UI framework that generates me the following headers
based on this configuration
(final result)
[
[
{
"title": "Section 1",
"rowspan": "4",
"colspan": "1"
},
{
"title": "Section 2",
"rowspan": "1",
"colspan": "2"
},
{
"title": "Section 3",
"rowspan": "1",
"colspan": "3"
},
{
"title": "Section 4",
"rowspan": "1",
"colspan": "1"
}
],
[
{
"title": "Section 2.1",
"rowspan": "3",
"colspan": "1"
},
{
"title": "Section 2.2",
"rowspan": "3",
"colspan": "1"
},
{
"title": "Section 3.1",
"rowspan": "3",
"colspan": "1"
},
{
"title": "Section 3.2",
"rowspan": "1",
"colspan": "2"
},
{
"title": "Section 4.1",
"rowspan": "1",
"colspan": "1"
}
],
[
{
"title": "Section 3.2.1",
"rowspan": "2",
"colspan": "1"
},
{
"title": "Section 3.2.2",
"rowspan": "2",
"colspan": "1"
},
{
"title": "Section 4.1.1",
"rowspan": "1",
"colspan": "1"
}
],
[
{
"title": "Section 4.1.1.1",
"rowspan": "1",
"colspan": "1"
}
]
]
I want to simplify the configuration. There should be just a tree like structure and I want to calculate the row- and colspans dynamically
(starting point)
[
{
"title": "Section 1"
},
{
"title": "Section 2",
"children": [
{
"title": "Section 2.1"
},
{
"title": "Section 2.2"
}
]
},
{
"title": "Section 3",
"children": [
{
"title": "Section 3.1"
},
{
"title": "Section 3.2",
"children": [
{
"title": "Section 3.2.1"
},
{
"title": "Section 3.2.2"
}
]
}
]
},
{
"title": "Section 4",
"children": [
{
"title": "Section 4.1",
"children": [
{
"title": "Section 4.1.1",
"children": [
{
"title": "Section 4.1.1.1"
}
]
}
]
}
]
}
]
I thought about how to map the starting point array to the final result array. These are my assumptions:
11My current approach
const configuredHeaders = [{
title: "Section 1"
},
{
title: "Section 2",
children: [{
title: "Section 2.1"
},
{
title: "Section 2.2"
}
]
},
{
title: "Section 3",
children: [{
title: "Section 3.1"
},
{
title: "Section 3.2",
children: [{
title: "Section 3.2.1"
},
{
title: "Section 3.2.2"
}
]
}
]
},
{
title: "Section 4",
children: [{
title: "Section 4.1",
children: [{
title: "Section 4.1.1",
children: [{
title: "Section 4.1.1.1"
}]
}]
}]
}];
const finalHeaders = [];
traverseColumnHeaders(configuredHeaders, -1); // first depth should start with 0
function traverseColumnHeaders(headers, parentDepth) {
headers.forEach(header => {
header.currentDepth = parentDepth + 1;
if (header.children) {
traverseColumnHeaders(header.children, header.currentDepth);
header.colspan = header.children.reduce((currentSum, child) => currentSum + child.colspan, 0); // sum of child colspans
header.rowspan = 1;
} else {
header.colspan = 1;
// header.rowspan = ... maximum depth - header.currentDepth ...
}
addHeaderToFinalHeaders(header);
});
}
function addHeaderToFinalHeaders({ currentDepth, title, rowspan, colspan }) {
const depthExistsInFinalHeaders = currentDepth in finalHeaders;
if (!depthExistsInFinalHeaders) {
finalHeaders[currentDepth] = [];
}
finalHeaders[currentDepth].push({ title, rowspan, colspan });
}
console.log(finalHeaders);
This one looks quite good to me because I only need to traverse the collection once. But as you can see some rowspan fields are not calculated yet because I don't know the maximum depth at this point.
To solve this I could initialize a global variable, search for the maximum depth like so
(I took the solution from here Getting the depth of a tree data structure in a simpler way for now)
function getMaximumDepth(headers) {
return getDepth(headers) -1;
};
function getDepth(headers) {
return 1 + Math.max(0, ...headers.map(({ children = [] }) => getDepth(children)));
}
const maximumDepth = getMaximumDepth(configuredHeaders);
and calculate
header.rowspan = maximumDepth - header.currentDepth
but now I have to traverse the structure twice. Is there a way to optimize my solution?