【问题标题】:Create a recursive function that takes a flat array and converts to a tree data structure创建一个递归函数,该函数采用平面数组并转换为树数据结构
【发布时间】:2019-05-17 04:38:03
【问题描述】:

所以我正在尝试编写一个递归函数,该函数将对象的平面数组及其值、id 和父节点的 id 转换为树结构,其中结构的子节点是一个数组的节点。子节点需要按id排序,如果null可以是根节点。

我试图编写函数 toTree(data) 的函数,应该只接受数据数组。没有父母,我无法做到这一点。到目前为止,我有一个函数(如下),它需要数据和父级才能开始。

输入:

 const tasks = [
  { id: 1, parent: null, value: 'Make breakfast' },
  { id: 2, parent: 1, value: 'Brew coffee' },
  { id: 3, parent: 2, value: 'Boil water' },
  { id: 4, parent: 2, value: 'Grind coffee beans' },
  { id: 5, parent: 2, value: 'Pour water over coffee grounds' }
];

输出:

{
  id: 1,
  parent: null,
  value: 'Make Breakfast',
  children: [
     {
       id: 2,
       parent: 1,
       value: 'Brew coffee',
       children: [
          { id: 3, parent: 2, value: 'Boil water' },
          { id: 4, parent: 2, value: 'Grind coffee beans' },
          { id: 5, parent: 2, value: 'Pour water over coffee grounds'     }
       ]
     }
  ]
}


funciton toTree(data) {
  customtoTree (data, null);
}

function customToTree (data, parent) {
  const out = [];
  data.forEach((obj) => {
    if (obj.parent === parent) {
      const children = customToTree(data,obj.parent);

      if (children.length) {
        obj[children[0]] = children;
      }
      const {id,parent, ...content} = obj;
      out.push(content);
    }
  });
  return out;
}

我真的很想了解如何做到这一点的正确逻辑,并考虑这个问题以及如何在不明确给出父母的情况下做到这一点。

【问题讨论】:

标签: javascript tree


【解决方案1】:

我在面试时遇到了同样的问题,但我一直没能解决。我也很困惑,该函数应该只将数组作为第一个也是唯一的参数。

但是在稍后对其进行修改之后(并得到了一位聪明人的一些非常好的建议),我意识到您可以在第一次调用该函数时将数组作为第一个也是唯一的参数,然后在递归调用期间传递父级作为第二个论点。

在函数内部,您只需要检查第二个参数是否未定义,如果是,则在数组中搜索您的根对象并将其分配给您的第二个参数。

所以这是我的解决方案,我希望它会更清楚:

function toTree(arr, item) {

        if (!item) {
            item = arr.find(item => item.parent === null)
        }

        let parent = {...item}
        parent.children = 
            arr.filter(x => x.parent === item.id)
                .sort((a, b) => a.id - b.id)
                .map(y => toTree(arr, y))

        return parent     
}

toTree(tasks)

【讨论】:

    【解决方案2】:

    我无法检查更多的测试用例,但这是我很快就能想出的东西,它通过了你的用例,它看起来不太好,我建议将它用作初始结构,然后在其上构建.另外,我假设任务按父级升序排序,即子级只会出现在任务数组中的父级之后

    const tasks = [
      { id: 1, parent: null, value: 'Make breakfast' },
      { id: 2, parent: 1, value: 'Brew coffee' },
      { id: 3, parent: 2, value: 'Boil water' },
      { id: 4, parent: 2, value: 'Grind coffee beans' },
      { id: 5, parent: 2, value: 'Pour water over coffee grounds' },
      { id: 6, parent: 5, value: 'Pour water over coffee grounds' },
      { id: 7, parent: 5, value: 'Pour water over coffee grounds' }
    ];
    
    function Tree() {
      this.root = null;
      // this function makes node root, if root is empty, otherwise delegate it to recursive function
      this.add = function(node) {
        if(this.root == null)
          this.root = new Node(node);
        else
          // lets start our processing by considering root as parent
          this.addChild(node, this.root);
      }
    
      this.addChild = function(node, parent) {
        // if the provided parent is actual parent, add the node to its children
        if(parent.id == node.parent) {
          parent.children[node.id] = new Node(node);
        } else if(parent.children[node.parent]) {
          // if the provided parent children contains actual parent call addChild with that node
          this.addChild(node, parent.children[node.parent])
        } else if(Object.keys(parent.children).length > 0) {
          // iterate over children and call addChild with each child to search for parent
          for(let p in parent.children) {
            this.addChild(node, parent.children[p]);
          }
        } else {
          console.log('parent was not found');
        }
      }
    }
    
    function Node (node) {
      this.id = node.id;
      this.parent = node.parent;
      this.value = node.value;
      this.children = {};
    }
    
    const tree = new Tree();
    
    // We are assuming that tasks are sorted in ascending order by parent
    
    for(let t of tasks) {
      tree.add(t);
    }
    
    console.log(JSON.stringify(tree.root))
    

    如果您有任何问题,请告诉我。一起来破解吧

    【讨论】:

      【解决方案3】:

      如果您的输入已经按 id 排序,并且列表中没有子节点可以排在其父节点之前,那么您可以在一个循环中执行此操作,甚至不需要递归:

       const tasks = [
        { id: 1, parent: null, value: 'Make breakfast' },
        { id: 2, parent: 1, value: 'Brew coffee' },
        { id: 3, parent: 2, value: 'Boil water' },
        { id: 4, parent: 2, value: 'Grind coffee beans' },
        { id: 5, parent: 2, value: 'Pour water over coffee grounds' }
      ];
      
      const tasksById = Object.create(null);
      
      // abusing filter to do the work of a forEach() 
      // while also filtering the tasks down to a list with `parent: null`
      const root = tasks.filter((value) => {
        const { id, parent } = value;
        
        tasksById[id] = value;
        
        if(parent == null) return true;
        
        (tasksById[parent].children || (tasksById[parent].children = [])).push(value);
      });
      
      console.log("rootNodes", root);
      console.log("tasksById", tasksById);
      .as-console-wrapper{top:0;max-height:100%!important}

      【讨论】:

        猜你喜欢
        • 2013-04-13
        • 2016-03-18
        • 1970-01-01
        • 1970-01-01
        • 2011-11-25
        • 2020-09-16
        • 2015-11-08
        • 2022-10-04
        • 2018-08-27
        相关资源
        最近更新 更多