Say I have this piece of demo data:
{
size: 100,
type: 'container',
list: [
{
size: 30,
type: 'container',
list: [
{
size: 10,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10]
},
{
size: 15,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
},
{
size: 25,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
}
]
},
{
size: 50,
type: 'container',
list: [
{
size: 20,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
},
{
size: 25,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
},
{
size: 25,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
}
,
{
size: 30,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
}
]
},
{
size: 20,
type: 'container',
list: [
{
size: 5,
type: 'leaf',
list: [1,2,3,4,5]
},
{
size: 15,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
}
]
}
]
}
Note, I just filled the so-called "leaf" nodes with integers to show their array positions. But they could be filled with any JavaScript objects (Arrays, objects, strings, numbers, etc.). The leaf nodes can have max 32 items, but I don't think that really matters for this question. The container nodes can only have 32 direct children as well.
How do you say getLeafContaining(tree, index)
, where it will return you the leaf which has the item at the global index
, as well as the relative index. I say "global index" because this is the index of the leaf node if you were to take all of the leaf nodes as sequential.
What I have done so far is this:
const getLeafContaining = (tree, index) => {
if (index > tree.size - 1) {
return { node: null, index: -1 }
}
let nodes = [tree]
let startSize = 0
a:
while (true) {
b:
for (let i = 0, n = nodes.length; i < n; i++) {
let node = nodes[i]
let endSize = startSize + node.size
if (startSize <= index && index <= endSize) {
if (node.type == 'container') {
nodes = node.list
break b
} else {
let relativeIndex = index - startSize
return { node, index: relativeIndex }
}
} else {
startSize = endSize
}
}
}
}
const tree = {
size: 100,
type: 'container',
list: [
{
size: 30,
type: 'container',
list: [
{
size: 10,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10]
},
{
size: 15,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
},
{
size: 25,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
}
]
},
{
size: 50,
type: 'container',
list: [
{
size: 20,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
},
{
size: 25,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
},
{
size: 25,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
}
,
{
size: 30,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
}
]
},
{
size: 20,
type: 'container',
list: [
{
size: 5,
type: 'leaf',
list: [1,2,3,4,5]
},
{
size: 15,
type: 'leaf',
list: [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
}
]
}
]
}
console.log(getLeafContaining(tree, 22))
It seems to be correct but I can't tell. How to you robustly implement this?