简体   繁体   English

从 Angular 中的平面数组创建树数组

[英]Create a Tree array from a flat array in Angular

I need to make a tree Array to use in primeng tree component, but I receive from back end a flat array.我需要制作一个树数组以在 primeng 树组件中使用,但我从后端收到一个平面数组。

Example that I receive:我收到的例子:

{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'},
]

and I need transform in:我需要转换:

[
{label: 'name', data: 'object origial', draggable: true, droppable: true, children: []}
]

In first of all, i try make the original array in objects that I need with this function首先,我尝试用这个 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)
})

and this works, but I don't know how I can Read this new array to make de object that have the previous name equal the name and put in the children.这行得通,但我不知道如何读取这个新数组,使以前的名称等于名称的 de object 放入子项中。

Anyone can help me please???任何人都可以帮助我吗???

For concreteness, I will define your array like this具体来说,我会这样定义你的数组

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' },
]

where Data is the following interface:其中Data是以下接口:

interface Data {
  name: string,
  previousName: string,
  showOrder: string;
  preferredOrder: string
}

And the goal is to implement the makeTreeNode() function with the following call signature:目标是使用以下调用签名实现makeTreeNode() function:

declare function makeTreeNode(array: Data[]): Tree<Data>[];

where Tree is a generic class like其中Tree通用的 class,例如

class Tree<T> {
  constructor(
    public label: string,
    public data: T,
    public children: Tree<T>[] = [],
    public draggable = true,
    public droppable = true
  ) { }
}

Here's one possible approach:这是一种可能的方法:

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)
  );
  
}

There are three steps:分为三个步骤:

  • For each Data element, create a corresponding Tree<Data> node (with an empty children array) and put it in nodeMap at the key corresponding to the element name .对于每个Data元素,创建一个相应的Tree<Data>节点(带有一个空的children数组)并将其放在nodeMap中与元素name对应的键处。 This lets us easily look up nodes by name later.这使我们以后可以轻松地按名称查找节点。

  • For each Data element, find the corresponding node in nodeMap , and push it onto the children array of the node corresponding to the name of its parent .对于每个Data元素,在nodeMap中找到对应的节点,并将其推送到与其parent名称对应的节点的children数组中。 When this is done, all the nodes' children arrays will be fully populated.完成后,所有节点的children节点 arrays 将被完全填充。

  • Filter the array of Tree<Data> elements in the values of nodeMap so that we only keep those elements that have no parent element in nodeMap .nodeMap的值中过滤Tree<Data>元素的数组,以便我们只保留nodeMap中没有父元素的那些元素。 This is an array of the root elements, and it is this array that we return.这是一个根元素数组,我们返回的就是这个数组。


Let's test it out:让我们测试一下:

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: []]" 

Looks good, we now have a tree structure with two root nodes.看起来不错,我们现在有一个包含两个根节点的树结构。


Note that the implementation of makeTreeNode() could be improved to avoid an extra loop through the array, by collapsing the last two steps into one:请注意,可以改进makeTreeNode()的实现以避免通过数组的额外循环,方法是将最后两个步骤合并为一个:

// populate children and return array
const ret: Tree<Data>[] = [];
array.forEach(element =>
  (nodeMap[element.previousName]?.children ?? ret).push(nodeMap[element.name])
)
return ret;

But I presented the original version since it demonstrates the concepts more clearly.但我展示了原始版本,因为它更清楚地展示了概念。

Playground link to code 游乐场代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM