[英]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.