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

时间:2017-06-01 19:34:23

标签: javascript

注意:下面的解决方案!

问题: 我需要代码将具有id和parent值的平面对象数组转换为树。由于平面数组是动态生成的,因此深度级别的数量是未知的。

此外,一旦项目在树中,我需要为节点分配一个级别属性值,具体取决于它们所在的树级别(根节点=级别0,根的直接子节点=级别1,子节点孩子= 2级等)。

最后,每个树级别的节点应按其ID进行alpha排序。所以应该对root id进行排序,然后根据孩子,然后是孩子的孩子等等。

我发现一些解决方案至少满足了我的两个要求,但没有一个满足这三个要求。

解决方案: 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: []} 
];

进入这个:

<!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>

2 个答案:

答案 0 :(得分:0)

您可以先构建树对象,然后渲染所需的html结构。

为了获得排序结果,我建议先使用两级方法对数据进行排序,先排序parent,然后排序id

要返回所需级别,您可以将level变量添加到getTree,如果没有设置则初始化为零。

每个更深层次的增量值。

&#13;
&#13;
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);
&#13;
&#13;
&#13;

答案 1 :(得分:-1)

如果我的小提琴消失了,这是我的完整解决方案:

<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>