Convert parent-child array to tree

前端 未结 7 1846
感动是毒
感动是毒 2020-12-04 22:31

Can anyone help converting the following list of parent-child objects:

[
   {
      \"name\":\"root\",
      \"_id\":\"root_id\",
   },
   {
      \"name\":\"a1\"         


        
相关标签:
7条回答
  • 2020-12-04 22:58

    Give it a try:

       var obj = {};
       obj.rootElements = [];
       var currentRoot;
       var currentParent;
       for (s in a) {
           var t = a[s];
           var id = t._id;
           if (t.parentAreaRef) {
               var parentId = t.parentAreaRef.id;
               if (parentId == currentParent._id) {
                   //add children
                   if (!currentParent.children) {
                       currentParent.children = [];
                   }
                   currentParent.children.push(t);
               }
               else {
                   addChildToParent(t, parentId);
               }
    
           }
           else // is root
           {
               currentRoot = t;
               currentParent = t;
               obj.rootElements.push(currentRoot);
           }
       }
    
       var t = currentRoot
    
       function addChildToParent(child, parentId, root) {
           for (p in a) {
               if (a[p]._id.toString() == parentId.toString()) {
                   if (!a[p].children) {
                       a[p].children = [];
                   }
                   a[p].children.push(t);
               }
           }
       }
    
    0 讨论(0)
  • 2020-12-04 23:00

    There is an error in your string

    a[p].children.push(t);
    

    It should be

    a[p].children.push(child);
    

    also I'm little optimize it:

    var data = [{"id":1,"name":"X","parentId":null},{"id":2,"name":"Y","parentId":1},{"id":3,"name":"D","parentId":2},{"id":2,"name":"S","parentId":1},{"id":5,"name":"K","parentId":4}]
        var obj = {};
        obj.rootElements = [];
        for (i in data) {
            var _elem = data[i];
            if (_elem.parentId) {
                var _parentId = _elem.parentId;
                if (_parentId == _elem.id) {
                    // check children, if false - add
                    if (!_elem.children) {
                        _elem.children = [];
                    }
                    _elem.children.push(_elem);
                }
                else {
                    addChildToParent(_elem, _parentId);
                }
            }
            else // is root
            {
                obj.rootElements.push(_elem);
            }
        }
        function addChildToParent(child, parentId, root) {
            for (j in data) {
                if (data[j].id.toString() == parentId.toString()) {
                    if (!data[j].children) {
                        data[j].children = [];
                    }
                    data[j].children.push(child);
                }
            }
        }
        res.send(obj.rootElements); 
    
    0 讨论(0)
  • 2020-12-04 23:02

    You can use array-to-tree module from npm.

    0 讨论(0)
  • 2020-12-04 23:03

    I know it's late, but I just finished this algorithm and maybe it can help some other people looking to solve the same problem: http://jsfiddle.net/akerbeltz/9dQcn/

    A good thing about it is that it doesn't requires any special sort on the original object.

    If you need to adapt it to your needs change the following lines:

    1. Change the _id and the parentAreaRef.id depending on your structure.

      if (String(tree[i]._id) === String(item.parentAreaRef.id)) {

    2. Change the parentAreaRef depending on your structure.

      if (tree[idx].parentAreaRef) buildTree(tree, tree.splice(idx, 1)[0])

    Hope it helps!

    UPDATE

    Adding code here based on @Gerfried comment:

    var buildTree = function(tree, item) {
        if (item) { // if item then have parent
            for (var i=0; i<tree.length; i++) { // parses the entire tree in order to find the parent
                if (String(tree[i]._id) === String(item.parentAreaRef.id)) { // bingo!
                    tree[i].childs.push(item); // add the child to his parent
                    break;
                }
                else buildTree(tree[i].childs, item); // if item doesn't match but tree have childs then parses childs again to find item parent
            }
        }
        else { // if no item then is a root item, multiple root items are supported
            var idx = 0;
            while (idx < tree.length)
                if (tree[idx].parentAreaRef) buildTree(tree, tree.splice(idx, 1)[0]) // if have parent then remove it from the array to relocate it to the right place
                else idx++; // if doesn't have parent then is root and move it to the next object
        }
    }
    
    for (var i=0; i<data.length; i++) { // add childs to every item
        data[i].childs = [];
    }
    buildTree(data);
    console.log(data);
    

    Thanks!

    0 讨论(0)
  • 2020-12-04 23:05

    I know I'm too late, but since I just finished my contribution to a sample implementation of how this can be done I thought I would share it, since it might be found useful / or give inspiration to an alternative solution.

    The implementation can be found here: http://jsfiddle.net/sw_lasse/9wpHa/

    The main idea of the implementation centers around the following recursive function:

    // Get parent of node (recursive)
    var getParent = function (rootNode, rootId) {
    
        if (rootNode._id === rootId)
            return rootNode;
    
        for (var i = 0; i < rootNode.children.length; i++) {
            var child = rootNode.children[i];
            if (child._id === rootId)
                return child;
    
            if (child.children.length > 0)
                var childResult = getParent(child, rootId);
    
            if (childResult != null) return childResult;
        }
        return null;
    };
    

    ... that is used to build the tree.

    0 讨论(0)
  • 2020-12-04 23:10

    Borrowing the caching logic from Vivin Paliath's answer, I have created a reusable function to convert a list of data with child-parent relationships into a tree.

    var data = [
      { "id" : "root"                     },
      { "id" : "a1",   "parentId" : "root", },
      { "id" : "a2",   "parentId" : "a1",   },
      { "id" : "a3",   "parentId" : "a2",   },
      { "id" : "b1",   "parentId" : "root", },
      { "id" : "b2",   "parentId" : "b1",   },
      { "id" : "b3",   "parentId" : "b1",   }
    ];
    var options = {
      childKey  : 'id',
      parentKey : 'parentId'
    };
    var tree = walkTree(listToTree(data, options), pruneChildren);
    
    document.body.innerHTML = '<pre>' + JSON.stringify(tree, null, 4) + '</pre>';
    
    function listToTree(list, options) {
      options = options || {};
      var childKey    = options.childKey    || 'child';
      var parentKey   = options.parentKey   || 'parent';
      var childrenKey = options.childrenKey || 'children';
      var nodeFn      = options.nodeFn      || function(node, name, children) {
        return { name : name, children : children };
      };
      var nodeCache = {};
      return list.reduce(function(tree, node) {
        node[childrenKey] = [];
        nodeCache[node[childKey]] = node;
        if (typeof node[parentKey] === 'undefined' || node[parentKey] === '') {
          tree = nodeFn(node, node[childKey], node[childrenKey]);
        } else {
          parentNode = nodeCache[node[parentKey]];
          parentNode[childrenKey].push(nodeFn(node, node[childKey], node[childrenKey]));
        }
        return tree;
      }, {});
    }
    
    function walkTree(tree, visitorFn, parent) {
      if (visitorFn == null || typeof visitorFn !== 'function') {
        return tree;
      }
      visitorFn.call(tree, tree, parent);
      if (tree.children && tree.children.length > 0) {
        tree.children.forEach(function(child) {
          walkTree(child, visitorFn, tree);
        });
      }
      return tree;
    }
    
    function pruneChildren(node, parent) {
      if (node.children.length < 1) {
        delete node.children;
      }
    }

    0 讨论(0)
提交回复
热议问题