-1

这可能是一个典型的任务,但我没有在 Wiki 或这里找到一个优雅的解决方案。

我有一个包含下一个字段的元素列表:类型('c' 或 'e' - 容器或元素)、id级(0 或 id)。我需要像这样对它们进行排序

• [1] container 1
— [2] child element
— [3] child element
• [4] container 2
— [5] child element
— [6] child element
• [7] element without parent (parent: 0)
• [8] element without parent

只能有2个级别,但可以有一百多个元素。如果采取一个事实,它在浏览器中很重要——人们会因为页面冻结而诅咒:(所以,我正在寻找漂亮的解决方案。

UPD我写了解决方案,它不是很漂亮,但只使用了 2 次迭代(一次用于计数,一次用于更新。顺便说一下,如果有人会使用它:不按 ID 排序,如果需要,您应该添加此功能!)。

PS 有 3 行 jquery .append 来说明结果,仅此而已。

PPS 有没有办法只在第一个完成时才调用第二个 forEach,除了承诺?我在最后一个列表的元素上调用它,但不确定它是否正确。

4

3 回答 3

1

“超过一百个元素”的循环不会花费太多时间来冻结页面......

可以使用循环

1) Take all Containers in an array. (say arrContainers)
2) Iterate over the containers one-by-one.
3) If the container does not have elements, then add them to another array (say arrEmptyContainers)
3) If the container has childs, add each container in an array (say arrFinalList) followed by its elements.
4) Append arrEmptyContainers under arrFinalList.

希望能帮助到你...

于 2013-10-16T10:22:02.713 回答
1

您可以使用 object 作为关联数组一次性完成这项工作:

var test_items = [
    { title:'child element 2.2', type:'e', id:6, parent:4 },
    { title:'child element 2.1', type:'e', id:5, parent:4 },
    { title:'container 1', type:'c', id:1, parent:0 },
    { title:'container 2', type:'c', id:4, parent:0 },
    { title:'child element 1.1', type:'e', id:2, parent:1 },
    { title:'child element 1.2', type:'e', id:3, parent:1 },
    { title:'element without parent A', type:'e', id:8, parent:0 },
    { title:'element without parent B', type:'e', id:7, parent:0 }
];

function itemsToTree2( items ) {
    var tree2 = {};
    for( var i=0; i<items.length; ++i ) {
        var item = items[i];
        if( item.type=='c' || item.parent==0 ) {
            if( !tree2[item.id] ) {
                var parent = { id:item.id, parent:0, children:[] };
                tree2[item.id] = parent;
            }
            tree2[item.id].title = item.title;
            tree2[item.id].type = 'c';
        } else {
            if( !tree2[item.parent] ) {
                var parent = { id:item.parent, parent:0, children:[] };
                tree2[item.parent] = parent;
            }
            tree2[item.parent].children.push(item);
        }
    }
    return tree2;
}

var test_tree2 = itemsToTree2(test_items);
console.log(test_tree2);

不确定它是否会明显更快......如果您知道每个容器都会出现在输入数据中的元素之前 - 上面的代码可以简化:

function itemsToTree2( items ) {
    var tree2 = {};
    for( var i=0; i<items.length; ++i ) {
        var item = items[i];
        if( item.type=='c' || item.parent==0 ) {
            item.children = [];
            tree2[item.id] = item;
        } else {
            tree2[item.parent].children.push(item);
        }
    }
    return tree2;
}

如果您需要按字母顺序对树(按标题)进行级别(通常是这种情况),您将需要额外的处理:

function sortTree2( tree2, comparator ) {
    var tree2array = [];
    for( var id in tree2 )
        tree2array.push( tree2[id] );

    tree2array.sort(comparator);
    for( var i=0; i<tree2array.length; ++i )
        tree2array[i].children.sort(comparator);

    return tree2array;
}

var sorted_tree2 = sortTree2( test_tree2, function(a,b) {
    return a.title > b.title;
});
console.log(sorted_tree2);

也存在深度超过 2 层的树的通用解决方案。它使用类似的方法,并不比这复杂多少。

于 2013-10-16T11:39:45.560 回答
0

我自己的答案正在更新中。不是很好,但有效。

于 2013-10-17T09:24:55.030 回答