Get the level of a hierarchy

前端 未结 4 1827
心在旅途
心在旅途 2020-12-29 15:37

I have an array of objects, Where each object has an id and a ParentId property (so they can be arranged in trees). They are in no particular order

相关标签:
4条回答
  • 2020-12-29 15:59

    Here is your working code. Level starts at 2.

    ALERT: If a level cannot be calculated, the application may go into an infinite loop. So, make sure the parentId is valid for all objects and at least one of them have parentId="id-1".

    <script type="text/javascript">
        data = [
            {
                id:"id-2",
                parentId:"id-3"
            },
            {
                id:"id-4",
                parentId:"id-2"
            },
            {
                id:"id-3",
                parentId:"id-5"
            },
            {
                id:"id-5",
                parentId:"id-1"
            }
        ];
    
        function processData() {
            flag = true;
    
            while(flag) {
                flag = false;
    
                for(var i = 0; i < data.length; i++) {
                    if(data[i].parentId == "id-1") {
                        data[i].level = 2;
                    } else {
                        l = getLevel(data[i].parentId);
                        if(l > 0) {
                            data[i].level = l + 1;
                        } else {
                            flag = true;
                        }
                    }
                }
            }
        }
    
        function getLevel(id) {
            for(var i = 0; i < data.length; i++) {
                if(data[i].id == id) {
                    if(data[i].level) {
                        return data[i].level;
                    } else {
                        return 0;
                    }
                }
            }
    
            return 0;
        }
    
        processData();
    
        console.log(data);
    
    </script>
    
    0 讨论(0)
  • 2020-12-29 16:02

    A working example of the below code is on jsFiddle.

    Index the tree by id and traverse it upwards, from each node, and count until you hit the root. By indexing first, we approach O(n) time complexity (depending on tree density). ****Updated to satisfy the sorting requirement, and allow exclusion of root node***:

    function levelAndSort(data, startingLevel) {
        // indexes
        var indexed = {};        // the original values
        var nodeIndex = {};      // tree nodes
        var i;
        for (i = 0; i < data.length; i++) {
            var id = data[i].id;
            var node = {
                id: id,
                level: startingLevel,
                children: [],
                sorted: false
            };
            indexed[id] = data[i];
            nodeIndex[id] = node;
        }
    
        // populate tree
        for (i = 0; i < data.length; i++) {
            var node = nodeIndex[data[i].id];
            var pNode = node;
            var j;
            var nextId = indexed[pNode.id].parentId;
            for (j = 0; nextId in nodeIndex; j++) {
                pNode = nodeIndex[nextId];
                if (j == 0) {
                    pNode.children.push(node.id);
                }
                node.level++;
                nextId = indexed[pNode.id].parentId;
            }
        }
    
        // extract nodes and sort-by-level
        var nodes = [];
        for (var key in nodeIndex) {
            nodes.push(nodeIndex[key]);
        }
        nodes.sort(function(a, b) {
            return a.level - b.level;
        });
    
        // refine the sort: group-by-siblings
        var retval = [];
        for (i = 0; i < nodes.length; i++) {
            var node = nodes[i];
            var parentId = indexed[node.id].parentId;
            if (parentId in indexed) {
                var pNode = nodeIndex[parentId];
                var j;
                for (j = 0; j < pNode.children.length; j++) {
                    var child = nodeIndex[pNode.children[j]];
                    if (!child.sorted) {
                        indexed[child.id].level = child.level;
                        retval.push(indexed[child.id]);
                        child.sorted = true;
                    }
                }
            }
            else if (!node.sorted) {
                indexed[node.id].level = node.level;
                retval.push(indexed[node.id]);
                node.sorted = true;
            }
        }
        return retval;
    }
    

    Example:

    // level 0 (root) excluded
    var startingLevel = 1;
    var someData = [
        {id : "id-1", parentId : "id-0"},
        {id : "id-2", parentId : "id-0"},
        {id : "id-3", parentId : "id-2"},
        {id : "id-4", parentId : "id-3"},
        {id : "id-5", parentId : "id-4"},
        {id : "id-6", parentId : "id-4"},
        {id : "id-7", parentId : "id-0"},
        {id : "id-8", parentId : "id-1"},
        {id : "id-9", parentId : "id-7"},
        {id : "id-10", parentId : "id-1"},
        {id : "id-11", parentId : "id-1"},
        {id : "id-12", parentId : "id-1"}
    ];
    var outputArray = levelAndSort(someData, startingLevel);
    

    Output:

    enter image description here

    Note

    If you change the input order, the sort comes out a little different, but it's still correct (i.e., in level-order, grouped by sibling).

    0 讨论(0)
  • 2020-12-29 16:03

    I'm not sure where you get the value for level so I'll assume that its just an integer. BTW, you can add the level property to each of your array's item by looping through it.

    for (var i = 0, l = data.length; i < l; i++) { 
        data[i].level = i
    }
    

    which will give

    data = [{id:"1", parentId:"3", level:0 }, {id:"2", parentId:"1", level:1 } ...]
    
    0 讨论(0)
  • 2020-12-29 16:18

    One way to address this without the need for recursion is to create a DOM hierarchy. For each item in the array, create a div and attach it to its parent. then walk the DOM and assign the levels (top is level 1, then add 1 for each child).

    I have set up a rough demo here: http://jsfiddle.net/4AqgM/

    An excerpt from the code:

    top.dataset.level="1";
    var topChildren=top.getElementsByTagName("div");
    for (var i=0;i<topChildren.length;i++) {
    topChildren[i].dataset.level=parseInt(topChildren[i].parentNode.dataset.level)+1;
    }
    
    0 讨论(0)
提交回复
热议问题