简体   繁体   English

如何从平面对象数组创建树数组,然后为每个树节点的级别编号并在每个级别对节点进行排序?

[英]How to create a tree array from a flat array of objects, then number each tree node's level and sort nodes at each level?

Note: Solution below! 注意:下面的解决方案!

The Problem: I needed code to turn a flat array of objects with id and parent values into a tree. 问题:我需要代码将带有id和父值的对象的平面数组变成一棵树。 The number of levels deep is unknown, since the flat array is generated dynamically. 由于平面数组是动态生成的,因此深层的数目是未知的。

Also, once the items are in a tree, I needed nodes to be assigned a level property value, depending on what tree level they're on (root nodes = level 0, the root's immediate child nodes = level 1, children's children = level 2, etc). 另外,一旦项目在树中,我就需要为节点分配级别属性值,具体取决于它们所在的树级别(根节点=级别0,根的直接子节点=级别1,子级的子节点=级别) 2,等等)。

Finally, nodes at each tree level should be alpha sorted by their id. 最后,每个树级别的节点应按其ID进行alpha排序。 So root ids should be sorted, then the roots children, then the children's children, etc etc. 因此,应该对根ID进行排序,然后对根孩子进行排序,然后对孩子的孩子进行排序等等。

I found some solutions that met at least two of my requirements, but none that met all three. 我发现一些解决方案至少满足我的两个要求,但没有一个满足所有三个要求。

Solution: jsfiddle 解决方案: jsfiddle

var x = [
{id: 10, parent: 0, children: []},
{id: 20, parent: 10, children: []},
{id: 30, parent: 10, children: []},
{id: 40, parent: 30, children: []},
{id: 50, parent: 30, children: []},
{id: 60, parent: 30, children: []},
{id: 70, parent: 20, children: []},
{id: 80, parent: 20, children: []},
{id: 90, parent: 40, children: []},
{id: 100, parent: 40, children: []}, 
{id: 95, parent: 40, children: []},
{id: 110, parent: 50, children: []}, 
{id: 120, parent: 60, children: []}, 
{id: 130, parent: 0, children: []},
{id: 140, parent: 130, children: []},
{id: 150, parent: 140, children: []},
{id: 160, parent: 140, children: []},
{id: 170, parent: 140, children: []},
{id: 180, parent: 160, children: []},
{id: 190, parent: 160, children: []},
{id: 200, parent: 190, children: []} 
];

Into this: 变成这个:

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <ul>
        <li>10
            <ul>
                <li>20
                    <ul>
                        <li>70</li>
                        <li>80</li>
                    </ul>
                </li>
                <li>30
                    <ul>
                        <li>40
                            <ul>
                                <li>90</li>
                                <li>95</li>
                                <li>100</li>
                            </ul>
                        </li>
                        <li>50
                            <ul>
                                <li>110</li>
                            </ul>
                        </li>
                        <li>60
                            <ul>
                                <li>120</li>
                            </ul>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
        <li>130
            <ul>
                <li>140
                    <ul>
                        <li>150</li>
                        <li>160
                            <ul>
                                <li>180</li>
                                <li>190
                                    <ul>
                                        <li>200</li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                        <li>170</li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</body>
</html>

You could build the tree object first and then render the wanted html structure. 您可以先构建树对象,然后呈现所需的html结构。

for getting sorted result, I suggest to sort the data in advance with using a two level approach by sorting parent first and then by id . 为了获得排序结果,我建议使用两级方法预先对数据进行排序,首先对parent级进行排序,然后对id进行排序。

To return a wanted level, you could add a level variable to getTree and initalize with zero if not set. 要返回所需的级别,可以将level变量添加到getTree ,如果未设置, getTree为零。

The increment this value for every deeper level. 在每个更深的级别增加此值。

 function getTree(array, level) { var ul = document.createElement('ul'); level = level || 0; array.forEach(function (a) { var li = document.createElement('li'); li.appendChild(document.createTextNode(a.id + ' level: ' + level)); Array.isArray(a.children) && li.appendChild(getTree(a.children, level + 1)); ul.appendChild(li); }); return ul; } var data = [{ id: 10, parent: 0 }, { id: 20, parent: 10 }, { id: 30, parent: 10 }, { id: 40, parent: 30 }, { id: 50, parent: 30 }, { id: 60, parent: 30 }, { id: 70, parent: 20 }, { id: 80, parent: 20 }, { id: 90, parent: 40 }, { id: 100, parent: 40 }, { id: 95, parent: 40 }, { id: 110, parent: 50 }, { id: 120, parent: 60 }, { id: 130, parent: 0 }, { id: 140, parent: 130 }, { id: 150, parent: 140 }, { id: 160, parent: 140 }, { id: 170, parent: 140 }, { id: 180, parent: 160 }, { id: 190, parent: 160 }, { id: 200, parent: 190 }], tree = function (data, root) { var r = [], o = {}; data.forEach(function (a) { a.children = o[a.id] && o[a.id].children; o[a.id] = a; if (a.parent === root) { r.push(a); } else { o[a.parent] = o[a.parent] || {}; o[a.parent].children = o[a.parent].children || []; o[a.parent].children.push(a); } }); return r; }(data.sort(function (a, b) { return a.parent - b.parent || a.id- b.id; }), 0); document.body.appendChild(getTree(tree)); console.log(tree); 

In case my fiddle ever disappears, here's my complete solution: 万一我的小提琴消失了,这是我完整的解决方案:

<html>

<script>
window.onload = function () {

// STEP 1: Get a flat array of objects.

/* A flat (1 dimensional) array, which can later be turned into a tree, since each array item has an id and parent property. */
var x = [
{id: 10, parent: 0, children: []}, // 2 immediate children, root node
{id: 20, parent: 10, children: []}, // 2 immediate children
{id: 30, parent: 10, children: []}, // 3 immediate children
{id: 40, parent: 30, children: []}, // 3 immediate children
{id: 50, parent: 30, children: []}, // 1 immediate children
{id: 60, parent: 30, children: []}, // 1 immediate children
{id: 70, parent: 20, children: []}, // 0 immediate children
{id: 80, parent: 20, children: []}, // 0 immediate children
{id: 90, parent: 40, children: []}, // 0 immediate children
{id: 100, parent: 40, children: []}, // 0 immediate children
{id: 95, parent: 40, children: []}, // 0 immediate children
{id: 110, parent: 50, children: []}, // 0 immediate children
{id: 120, parent: 60, children: []}, // 0 immediate children
{id: 130, parent: 0, children: []}, // 1 immediate children, root node
{id: 140, parent: 130, children: []}, // 3 immediate children
{id: 150, parent: 140, children: []}, // 0 immediate children
{id: 160, parent: 140, children: []}, // 2 immediate children
{id: 170, parent: 140, children: []}, // 0 immediate children
{id: 180, parent: 160, children: []}, // 0 immediate children
{id: 190, parent: 160, children: []}, // 1 immediate children
{id: 200, parent: 190, children: []} // 0 immediate children; 5 levels deep (level = 4, since start level is 0)
];


// STEP 2: Turn the flat array into a tree (hierarchical) array.

function tierData (arr) {
/* 
    Params: 
        @arr = flat array. Each array item is an object containing id, parent, and children properties.

    Description: 
        Takes a flat array and turns into into a tree (hierarchical) array.
*/
    for (var i = 0; i < arr.length; i++) {
        arr.forEach(function (n) {
            if (n.parent === arr[i].id) {
                arr[i].children.push(n);
            }           
        });
    }
    return arr.filter(function (n) { return n.parent === 0 }); // Only return root nodes and their children, children's children, etc.
}

var td = tierData(x);
//console.log(td);


// STEP 3: Assign a "level" property to each tree level. Numeric sort tree items for each level in the tree.

function treeSortAndLevel (treeArr,flatArr,flatIndex) {
/* 
    Params: 
        @treeArr = A tree (hierarchical) array, created from a flat array using the tierData fn.
        @flatArr = A flat array on which @treeArr is based.
        @flatIndex = DON'T PASS AN ARG. This is assigned a value by subsequent recursive fn calls. 

    Description: 
        Returns a tree which is numeric sorted at each level and each tree node is assigned a level property value, starting with root node(s) level = 0.
*/
    // If not provided (ie the fn's first call), create an indexer for the flat array.
    if (flatIndex === undefined) {
        var flatIndex = {};
        for (var i = 0; i < flatArr.length; i++) {
            flatIndex[flatArr[i].id] = flatArr[i];      
        }   
    }

    for (var i = 0; i < treeArr.length; i++) {
        // Numeric sort the current treeArr tier (ie array) by id.
        treeArr.sort(function (a, b) { return a.id - b.id; });
        // Determine and set the treeArr item's level.
        var parentId = treeArr[i].parent;
        var level = 0;
        while (parentId !== 0) {
            level++;
            var ancestor;
            ancestor = flatIndex[parentId];
            parentId = ancestor.parent;
        }
        treeArr[i].level = level;
        treeSortAndLevel(treeArr[i].children,flatArr,flatIndex);
    }
    return treeArr;
}

var sortedAndLeveldTree = treeSortAndLevel(td,x);

console.log(sortedAndLeveldTree);


// STEP 4: Append a multi-tiered unordered list to the DOM for the sorted and level numbered tree.

function printTree (treeArr) {
/* 
    Params:
        @treeArr = A tree (hierarchical) array, created from a flat array using the tierData fn.

    Description: 
        Prints a tree to the console. 
*/
    for (var i = 0; i < treeArr.length; i++) {  
        var indent = '';
        var level = treeArr[i].level;
        while (level > 0) {
            indent += '  --  ';
            level--;
        }
        console.log(indent + treeArr[i].id);    
        printTree(treeArr[i].children);
    }
}

function createTreeDOM (treeArr, ul) {
/* 
    Params:
        @treeArr = A tree (hierarchical) array, created from a flat array using the tierData fn.
        @ul = DON'T PASS AN ARG. This is assigned a value by subsequent recursive fn calls.

    Description: 
        Returns an unordered list tree (DOM element).
*/
    if (ul === undefined) {
        ul = document.createElement('ul');
    }
    for (var i = 0; i < treeArr.length; i++) {  
        var li = document.createElement('li');
        var tx = document.createTextNode(treeArr[i].id);
        li.appendChild(tx);
        if (treeArr[i].children.length > 0) {
            var subUL = document.createElement('ul');
            li.appendChild(subUL);
            createTreeDOM(treeArr[i].children, subUL);
        }
        ul.appendChild(li);
    }
    return ul;
}

// Alternatively, print the sorted and level numbered tree to the console in a tree-like style using the printTree fn:
//printTree(sortedAndLeveldTree);

var p = document.createElement('p');
p.innerHTML = 'The below tree was dynamically created from a flat array of objects using JS. Tree items (the objects, not the DOM elements) are assigned a level property, starting with 0 for root items. Tree items are sorted by their id at each tier (tree level).';
document.body.appendChild(p);

var treeDOM = createTreeDOM(sortedAndLeveldTree);
document.body.appendChild(treeDOM);

}
</script>

</html>

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

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