簡體   English   中英

從 Angular 中的平面數組創建樹數組

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM