如何从类似配置的父子数组项中以编程方式聚合树结构?
How to aggregate a tree structure programmatically from config-like parent-child array items?
我想将我的 javascript 对象结构更改为一个类似于层次结构树模式对象的对象,
这是我的对象:
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 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))
当我用下面的 id 更改 PID 值时,出现了一些我没想到的事情,
我的意思是,从 {'id':4 ,'pid' : 2}
到 {'id':4 ,'pid' : 9}
,
结果是 register[el.pid] is undefined
请帮忙解决这个问题,提前致谢
通过编程方式从 parent-child config-like 项目聚合树是可能的,即使这些项目不是完美的顺序,只要这些关系是有效的,因此是可表示的。
循环父子引用,就像 OP creates/triggers 将 { 'id': 4, 'pid': 2 }
更改为 { 'id': 4, 'pid': 9 }
时那样,将链接松散到一个已经可以表示的整体树结构中。因此,此类引用无效,并且链接到前者的任何其他有效子结构也将丢失。
以上声明通过下一个提供的示例代码证明了自己...
function aggregateTree(
{ index = {}, result = {} }, // accumulator.
{ id, pid }, // parent child config.
) {
const childItem = (index[id] ??= { [id]: {} });
const parentItem = (pid !== 0)
&& (index[pid] ??= { [pid]: {} })
|| null;
const node = (parentItem !== null)
&& parentItem[pid] // programmatically build partial trees.
|| result // assign partial tree references at root/resul level.
Object.assign(node, 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; }
嗯,您不能将父级移动到它自己的子级。这仅适用于时间旅行 novels/movies.
为了在不删除属性的情况下创建树,您可以进行一个循环并同时获取 id 和父级,结果是具有根父级的对象 0
。
这种方法也适用于未排序的数据。
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; }
我想将我的 javascript 对象结构更改为一个类似于层次结构树模式对象的对象, 这是我的对象:
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 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))
当我用下面的 id 更改 PID 值时,出现了一些我没想到的事情,
我的意思是,从 {'id':4 ,'pid' : 2}
到 {'id':4 ,'pid' : 9}
,
结果是 register[el.pid] is undefined
请帮忙解决这个问题,提前致谢
通过编程方式从 parent-child config-like 项目聚合树是可能的,即使这些项目不是完美的顺序,只要这些关系是有效的,因此是可表示的。
循环父子引用,就像 OP creates/triggers 将 { 'id': 4, 'pid': 2 }
更改为 { 'id': 4, 'pid': 9 }
时那样,将链接松散到一个已经可以表示的整体树结构中。因此,此类引用无效,并且链接到前者的任何其他有效子结构也将丢失。
以上声明通过下一个提供的示例代码证明了自己...
function aggregateTree(
{ index = {}, result = {} }, // accumulator.
{ id, pid }, // parent child config.
) {
const childItem = (index[id] ??= { [id]: {} });
const parentItem = (pid !== 0)
&& (index[pid] ??= { [pid]: {} })
|| null;
const node = (parentItem !== null)
&& parentItem[pid] // programmatically build partial trees.
|| result // assign partial tree references at root/resul level.
Object.assign(node, 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; }
嗯,您不能将父级移动到它自己的子级。这仅适用于时间旅行 novels/movies.
为了在不删除属性的情况下创建树,您可以进行一个循环并同时获取 id 和父级,结果是具有根父级的对象 0
。
这种方法也适用于未排序的数据。
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; }