【发布时间】:2021-04-15 14:22:48
【问题描述】:
我正在尝试使用元素中的后代和祖先参数将列表转换为树:
例如,我有这样的事情:
const itemToUpdate = {
id: 1,
ancestors: [
{
id: 2,
ancestors: [
{
id: 4
}
]
}
],
descendants: [
{
id: 3,
descendants: [
{
id: 5
},
{
id: 6,
descendants: [
{
id: 8
},
{
id: 9
}
]
},
{
id: 7
}
]
}
]
};
const updatedItem = {
id: 4,
children: [
{
id: 2,
children: [
{
id: 1,
children: [
{
id: 3,
children: [
{
id: 5
},
{
id: 6,
children: [
{
id: 8
},
{
id: 9
}
]
},
{
id: 7
}
]
}
]
}
]
}
]
};
关键是树可以嵌套很多层。此外,关卡上可能有很多祖先和后代,所以我需要一个更通用的解决方案。树必须从祖先向上创建,从后代向下创建。
我找到了一种获取树的后代的方法,但我仍然需要在这棵树的顶部添加祖先:
export const convertListToTree = <T extends ApiTree<T>>(list: Array<T>, key = 'ascendants'): Array<T> => {
const getNestedItem = (path: Array<string>, tree: Array<T>): T => {
const nestedItem = tree.find(nestedItem => nestedItem.id === path[0]);
const newPath = path.slice(1);
if (!newPath.length) {
return nestedItem;
} else if (nestedItem?.[key]) {
return getNestedItem(newPath, nestedItem?.[key]);
} else {
return getNestedItem(newPath, tree);
}
};
const sortListByPathLength = (list: Array<T>): Array<T> => {
return sortBy(list, (item: T) => item.path?.length);
};
const addRootItem = (item: T, tree: Array<T>): void => {
tree.push(item);
};
const addChildrenItem = (item: T, tree: Array<T>): void => {
const parent = getNestedItem(item.path, tree);
if (parent) {
parent[key].push(item);
} else {
addRootItem(item, tree);
}
};
const tree = [];
if (list?.length) {
const sortedList = sortListByPathLength(list);
sortedList.forEach(item => {
if (!item.path?.length) {
addRootItem(item, tree);
} else {
addChildrenItem(item, tree);
}
});
}
return tree;
};
任何建议都将受到欢迎。 ????
【问题讨论】:
-
如果您有多个项目怎么办?你试过什么?
-
抱歉,如果一个节点有多个祖先,应该怎么办?这对解决方案非常重要。
-
@NinaScholz 嗯,这是个好问题。我认为我们应该将一个或多个根级别降低,例如在这篇文章中:shareablecode.com/snippets/…
-
我不清楚多个祖先会发生什么?那么这棵树的根是什么?据我了解,在这种情况下没有树,而是有向无环图。请编辑您的问题并举例说明此类输入和预期输出。
-
@NinaScholz 你完全正确,对不起.. 每个节点可以有多个后代,但只有一个祖先。我用这种情况更新了这个例子。很抱歉造成混乱
标签: javascript typescript recursion tree traversal