I'd like to change my javascript object structure, into an object which is like hierarchy tree patern object, this is my object:
let input = [
{'id':1 ,'pid' : 0},
{'id':2 ,'pid' : 1},
{'id':3 ,'pid' : 2},
{'id':4 ,'pid' : 2},
{'id':5 ,'pid' : 3},
{'id':6 ,'pid' : 3},
{'id':7 ,'pid' : 4},
{'id':8 ,'pid' : 4},
{'id':9 ,'pid' : 4}
];
and found this snippet on the internet and it actually works well (i forgot who made it, thank you so much anyway)
let input = [
{'id':1 ,'pid' : 0},
{'id':2 ,'pid' : 1},
{'id':3 ,'pid' : 2},
{'id':4 ,'pid' : 2},
{'id':5 ,'pid' : 3},
{'id':6 ,'pid' : 3},
{'id':7 ,'pid' : 4},
{'id':8 ,'pid' : 4},
{'id':9 ,'pid' : 4}
];
let register = {};
let output = {};
for (let el of input) {
el = Object.assign({}, el);
register[el.id] = el;
if (!el.pid) {
output[el.id] = el;
} else {
register[el.pid][el.id] = el
}
delete el.pid;
delete el.id
}
document.body.innerHTML = "<pre>" (JSON.stringify(output, undefined, 2))
something i didn't expected came up when i change the PID value with the id from below,
i mean, from this {'id':4 ,'pid' : 2} into this {'id':4 ,'pid' : 9},
the result is register[el.pid] is undefined
please help to fix this, thanks in advance
CodePudding user response:
Well, you can not move the parent to it's own children. This works only in time travel novels/movies.
For creating a tree without deleting properties, you could take a single loop and take the id and parent as well and as result the object with the root parent 0.
This approach works with unsorted data as well.
const
input = [{ id: 1, pid: 0 }, { id: 2, pid: 1 }, { id: 3, pid: 2 }, { id: 4, pid: 2 }, { id: 5, pid: 3 }, { id: 6, pid: 3 }, { id: 7, pid: 4 }, { id: 8, pid: 4 }, { id: 9, pid: 4 }],
tree = {};
for (const { id, pid } of input) {
tree[pid] ??= {};
tree[id] ??= {};
tree[pid][id] ??= tree[id];
}
console.log(tree[0]);
.as-console-wrapper { max-height: 100% !important; top: 0; }
CodePudding user response:
Aggregating a tree programmatically from parent-child config-like items is possible even when such items are not in perfect order as long as such relationships are valid, thus representable.
Circular parent child references, like what the OP creates/triggers when changing { 'id': 4, 'pid': 2 } to { 'id': 4, 'pid': 9 }, loose the linkage into an already representable overall tree structure. Thus such references are invalid and any other valid substructure which is linked to the former is lost as well.
The above claim proves itself with the next provided example code ...
function aggregateTree(
{ index = {}, result = {} }, // accumulator.
{ id, pid }, // parent child config.
) {
const childItem = (index[id] ??= { [id]: {} });
const parentItem = (pid !== 0)
&& (index[pid] ??= { [pid]: {} })
|| null;
if (parentItem !== null) {
// programmatically build partial trees.
Object.assign(parentItem[pid], childItem);
} else {
// assign partial tree references
// at root/resul level.
Object.assign(result, childItem);
}
return { index, result };
}
console.log('unordered but valid parent child relationships ...', [
{ 'id': 1 ,'pid': 0 },
{ 'id': 2 ,'pid': 1 },
{ 'id': 3 ,'pid': 2 },
{ 'id': 12, 'pid': 0 },
{ 'id': 11, 'pid': 6 },
{ 'id': 10, 'pid': 6 },
{ 'id': 4, 'pid': 5 },
{ 'id': 5 ,'pid': 3 },
{ 'id': 6 ,'pid': 3 },
{ 'id': 7 ,'pid': 4 },
{ 'id': 8 ,'pid': 4 },
{ 'id': 9 ,'pid': 4 }
].reduce(aggregateTree, { result: {} }).result);
console.log('ordered but partially invalid parent child relationships ...', [
// circular references like 4 to 9 and 9 to 4,
// thus not being linked to the overall tree,
// can not be aggregated and displayed.
{ 'id': 1, 'pid': 0 },
{ 'id': 2, 'pid': 1 },
{ 'id': 3, 'pid': 2 },
{ 'id': 4, 'pid': 9 }, // circular thus disconnected.
// { 'id': 9, 'pid': 4 },
{ 'id': 5, 'pid': 3 },
{ 'id': 6, 'pid': 3 },
{ 'id': 7, 'pid': 4 }, // lost due to being linked to a circular reference.
{ 'id': 8, 'pid': 4 }, // lost due to being linked to a circular reference.
{ 'id': 9, 'pid': 4 }, // circular thus disconnected.
// { 'id': 4, 'pid': 9 },
].reduce(aggregateTree, { result: {} }).result);
.as-console-wrapper { min-height: 100%!important; top: 0; }
