const values = ["1.1.1.1.1", "1.1.1.1.2", "1.1.1.1.3", "1.1.1.1.4", "1.1.1.1.5", "1.2.1.1.1", "2.1.1.1.1", "2.2.1.1.1", "2.2.2.1.1", "2.2.3.1.1", "2.3.1.1", "2.3.2.1", "2.3.3.1", "2.3.4.1"]
// create a nested object from values
// 1.2.3 becomes {1:{2:{3:}}}
const transformedValues = (() => {
const output = {}
values.forEach(el => {
let tmp = output
el.split(".").forEach(val => {
if (!tmp[val]) {
tmp[val] = {}
}
tmp = tmp[val]
})
})
return output
})()
// find the object max depth, for the column count
const maxDepth = (function rec(obj, depth = 0){
return Math.max(depth, ...Object.values(obj).map(val => rec(val, depth + 1)))
})(transformedValues)
// header name generator (more than 26 and you'll go into non alphanumeric)
let headerASCII = "A".charCodeAt(0)
const getNextHeader = () => String.fromCharCode(headerASCII++)
// create the table
const table = document.createElement("table")
/*
@param {string} val the text of the created cell
@param {Object} next the childs of the object
@param {HTMLRowElement | null} row the last created
@param {boolean} newRow if we need to create a new row
@param {boolean} newHeader if we need to create a new thead
*/
function createTable(val, next, row, newRow = false, newHeader = false) {
// create new header
if (newHeader) {
const head = document.createElement("thead")
// with depth - 1 cells (first one takes 2 columns)
for (let i = 0; i < maxDepth - 1; i++) {
let th = document.createElement("th")
th.textContent = getNextHeader()
if(i === 0) {th.colSpan = 2}
head.appendChild(th)
}
table.appendChild(head)
}
// create new row
if (newRow) {
row = document.createElement("tr")
table.appendChild(row)
}
// new cell
const cell = document.createElement("td")
cell.textContent = val
// span on enought rows to align with every child
cell.rowSpan = (function childCount(obj) {return Object.values(obj).reduce((acc, el) => acc + childCount(el), 0) || 1})(next)
row.appendChild(cell)
// recurcive call
Object.entries(next).forEach(([key, value], i) => {
createTable(`${val}.${key}`, value, row, i !== 0)
})
}
// first call
Object.entries(transformedValues).forEach(([key, value]) => {
createTable(key, value, null, true, true)
})
document.body.append(table)
table {
border-collapse: collapse;
}
table th, table td {
border: 2px solid black;
}
table th {
background-color: cyan;
}