[英]Create a Tree array from a flat array in Angular
我需要制作一个树数组以在 primeng 树组件中使用,但我从后端收到一个平面数组。
我收到的例子:
{name: 'teste', previousName: 'fathername', showOrder: '1', preferredOrder: '2'},
{name: 'teste 2', previousName: 'fathername', showOrder: '1', preferredOrder: '2'},
{name: 'teste 3', previousName: 'teste', showOrder: '1', preferredOrder: '2'},
{name: 'teste 4', previousName: 'teste', showOrder: '1', preferredOrder: '2'},
{name: 'teste 5', previousName: 'teste 3', showOrder: '1', preferredOrder: '2'},
{name: 'teste 6', previousName: 'teste 5', showOrder: '1', preferredOrder: '2'},
]
我需要转换:
[
{label: 'name', data: 'object origial', draggable: true, droppable: true, children: []}
]
首先,我尝试用这个 function 在我需要的对象中创建原始数组
makeTreeNode(array) {
let arrTreeNode = []
let treeNodeObj;
array.filter(element => {
treeNodeObj = new tree() //tree is a class with the properties that I desire
treeNodeObj.label = element.name
treeNodeObj.data = element
treeNodeObj.draggable = true
treeNodeObj.droppable = true
arrTreeNode.push(treeNodeObj)
})
这行得通,但我不知道如何读取这个新数组,使以前的名称等于名称的 de object 放入子项中。
任何人都可以帮助我吗???
具体来说,我会这样定义你的数组
const arr: Data[] = [
{ name: 'teste', previousName: 'fathername', showOrder: '1', preferredOrder: '2' },
{ name: 'teste 2', previousName: 'fathername', showOrder: '1', preferredOrder: '2' },
{ name: 'teste 3', previousName: 'teste', showOrder: '1', preferredOrder: '2' },
{ name: 'teste 4', previousName: 'teste', showOrder: '1', preferredOrder: '2' },
{ name: 'teste 5', previousName: 'teste 3', showOrder: '1', preferredOrder: '2' },
{ name: 'teste 6', previousName: 'teste 5', showOrder: '1', preferredOrder: '2' },
]
其中Data
是以下接口:
interface Data {
name: string,
previousName: string,
showOrder: string;
preferredOrder: string
}
目标是使用以下调用签名实现makeTreeNode()
function:
declare function makeTreeNode(array: Data[]): Tree<Data>[];
其中Tree
是通用的 class,例如
class Tree<T> {
constructor(
public label: string,
public data: T,
public children: Tree<T>[] = [],
public draggable = true,
public droppable = true
) { }
}
这是一种可能的方法:
function makeTreeNode(array: Data[]) {
// keep a mapping from node name to node:
const nodeMap: Record<string, Tree<Data>> = {};
array.forEach(element =>
nodeMap[element.name] = new Tree(element.name, element)
);
// populate the children
array.forEach(element =>
nodeMap[element.previousName]?.children.push(nodeMap[element.name])
);
// return only the nodes without a parent
return Object.values(nodeMap).filter(n =>
!(n.data.previousName in nodeMap)
);
}
分为三个步骤:
对于每个Data
元素,创建一个相应的Tree<Data>
节点(带有一个空的children
数组)并将其放在nodeMap
中与元素name
对应的键处。 这使我们以后可以轻松地按名称查找节点。
对于每个Data
元素,在nodeMap
中找到对应的节点,并将其推送到与其parent名称对应的节点的children
数组中。 完成后,所有节点的children
节点 arrays 将被完全填充。
在nodeMap
的值中过滤Tree<Data>
元素的数组,以便我们只保留nodeMap
中没有父元素的那些元素。 这是一个根元素数组,我们返回的就是这个数组。
让我们测试一下:
function displayTreeNodes(array: Tree<Data>[]): string {
return "[" + array.map(t => t.label + ": " + displayTreeNodes(t.children)).join(", ") + "]"
}
console.log(displayTreeNodes(rootNodes));
// "[teste: [teste 3: [teste 5: [teste 6: []]], teste 4: []], teste 2: []]"
看起来不错,我们现在有一个包含两个根节点的树结构。
请注意,可以改进makeTreeNode()
的实现以避免通过数组的额外循环,方法是将最后两个步骤合并为一个:
// populate children and return array
const ret: Tree<Data>[] = [];
array.forEach(element =>
(nodeMap[element.previousName]?.children ?? ret).push(nodeMap[element.name])
)
return ret;
但我展示了原始版本,因为它更清楚地展示了概念。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.