Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 将数据排序到树中_Javascript_Sorting - Fatal编程技术网

Javascript 将数据排序到树中

Javascript 将数据排序到树中,javascript,sorting,Javascript,Sorting,我有以下数据: var data = [ { index : 1, sort : 10, parent : 0 }, { index : 2, sort : 7, parent : 0 }, { index : 3, sort : 15, parent : 1 }, { index : 4, sort : 4, parent : 0 }, { index : 5, sort : 13, parent : 1 }, { index : 6, sort

我有以下数据:

var data = [
    { index : 1, sort : 10, parent : 0 },
    { index : 2, sort : 7, parent : 0 },
    { index : 3, sort : 15, parent : 1 },
    { index : 4, sort : 4, parent : 0 },
    { index : 5, sort : 13, parent : 1 },
    { index : 6, sort : 20, parent : 5 },
    { index : 7, sort : 2, parent : 8 },
    { index : 8, sort : 6, parent : 5 },
];
如何根据父ID和排序值对其进行有效排序,以便最终得到:

var data = [
    { index : 4, sort : 4, parent : 0 },    
    { index : 2, sort : 7, parent : 0 },
    { index : 1, sort : 10, parent : 0 },
    { index : 5, sort : 13, parent : 1 },
    { index : 8, sort : 6, parent : 5 },
    { index : 7, sort : 2, parent : 8 },
    { index : 6, sort : 20, parent : 5 },   
    { index : 3, sort : 15, parent : 1 },
];
这是一个树形结构。每个元素后面紧跟着任何子元素,同一分支上的所有元素都按排序值排序

我能想到的最好办法是先按父级排序,然后对每个分支进行第二次排序。这似乎效率低下

编辑:示例排序顺序错误。我已经改正了

编辑以澄清:每个嵌套分支都需要显示在父值的正下方,而不是分支的末尾


编辑:进一步更正数据。

编辑:删除此项,它不起作用

这是我做的最好的了。哪个应该排序呢。我还没有测试过。我会留下最好的答案,看看是否有人能改进它

data.sort(function(a, b) {
  return a.parent - b.parent;
});

var changes = true;
while (changes){
    changes = false;
    for (var i = 1; i < data.length; i++) {
        if(data[i].parent === data[i-1].parent && data[i].sort < data[i-1].sort){
            var tmp = data[i-1];
            data[i-1] = data[i];
            data[i] = tmp;
            changes = true;   
        }
    }
}
data.sort(函数(a,b){
返回a.parent-b.parent;
});
var变化=真;
while(更改){
更改=错误;
对于(变量i=1;i
经过多次尝试,我终于想出了这个办法。它可以工作,但不是很优雅。也可以将其抽象到自己的类中

// Initial sort places items in the correct sort order.
data.sort(function(a, b) {
  return a.sort - b.sort;
});

vat top_parent_id = 1;          // The value of an items parent if it is a top level item.
var sorted = [];                // Empty array to copy sorted elements into.
var skipped = true;             // flag to indicate if any elements have been skipped.
var skip_count = 0;             // Counter to prevent infinite loops.
// Loop until no elements have been skipped. 
//This loops through each level of the tree until all nested branches have been added
while(skipped){
    skipped = false;
    skip_count++;
    if(skip_count === 50){      // Maximum tree depth.
        throw "Error in sorted data or tree depth too great.";
        break;
    }

    // Loop through the data in reverse order; this preserves the branch sort order.
    for (var i = data.length - 1; i >= 0; i--) {
        var item = data[i];

        // Skip if this element has already been processed.
        if(item.done)
            continue;

        // If this is this a top level item, then insert and continue.
        if(item.parent == top_parent_id){
            sorted.splice(0, 0, item);          // Insert at the start; last item is the top sort.
            item.done = true;
            continue;
        }

        // Loop the new array to try and find this items parent.
        var found = false;
        for (var j = 0; j < sorted.length; j++) {
            if(item.parent === sorted[j].index){
                sorted.splice(j + 1, 0, item);
                found = true;
                item.done = true;
                break;
            }
        }

        // If a place for an item has not been found then skip it for now so it can be tested again on the next iteration.
        if(!found){
            skipped = true;

        }
    }
}
data = sorted;
//初始排序将项目按正确的排序顺序放置。
数据排序(函数(a,b){
返回a.sort-b.sort;
});
增值税顶部父项id=1;//项目父级的值(如果它是顶级项目)。
变量排序=[];//将已排序元素复制到的空数组。
var skipped=true;//指示是否跳过了任何元素的标志。
var skip_count=0;//计数器以防止无限循环。
//循环,直到没有跳过任何元素。
//这将循环遍历树的每个级别,直到添加了所有嵌套的分支
while(跳过){
跳过=错误;
跳过计数++;
如果(跳过计数===50){//最大树深度。
抛出“排序数据错误或树深度太大”;
打破
}
//以相反的顺序遍历数据;这将保留分支排序顺序。
对于(var i=data.length-1;i>=0;i--){
var项目=数据[i];
//如果此元素已被处理,则跳过。
如果(项目完成)
继续;
//如果这是顶级项目,请插入并继续。
if(item.parent==top\u parent\u id){
sorted.splice(0,0,item);//在开头插入;最后一项是最上面的排序。
item.done=true;
继续;
}
//循环新数组以尝试查找此项的父项。
var=false;
对于(var j=0;j
这不是您最初的方法,但您可以根据数据构建实际的树,如下所示:

function TreeNode(data) {
  this.data     = data;
  this.parent   = null;
  this.children = [];
}
TreeNode.comparer = function (a, b) { 
  return a.data.sort < b.data.sort ? 0 : 1; 
};
TreeNode.prototype.sortRecursive = function () {
  this.children.sort(TreeNode.comparer);
  for (var i=0, l=this.children.length; i<l; i++) {
    this.children[i].sortRecursive();
  }
  return this;
};

function toTree(data) {
  var nodeById = {}, i = 0, l = data.length, node;

  nodeById[0] = new TreeNode(); // that's the root node

  for (i=0; i<l; i++) {  // make TreeNode objects for each item
    nodeById[ data[i].index ] = new TreeNode(data[i]);
  }
  for (i=0; i<l; i++) {  // link all TreeNode objects
    node = nodeById[ data[i].index ];
    node.parent = nodeById[node.data.parent];
    node.parent.children.push(node);
  }
  return nodeById[0].sortRecursive();
}
tree.walk(function () { console.log(this.data) }, true);
这样称呼它:

function TreeNode(data) {
  this.data     = data;
  this.parent   = null;
  this.children = [];
}
TreeNode.comparer = function (a, b) { 
  return a.data.sort < b.data.sort ? 0 : 1; 
};
TreeNode.prototype.sortRecursive = function () {
  this.children.sort(TreeNode.comparer);
  for (var i=0, l=this.children.length; i<l; i++) {
    this.children[i].sortRecursive();
  }
  return this;
};

function toTree(data) {
  var nodeById = {}, i = 0, l = data.length, node;

  nodeById[0] = new TreeNode(); // that's the root node

  for (i=0; i<l; i++) {  // make TreeNode objects for each item
    nodeById[ data[i].index ] = new TreeNode(data[i]);
  }
  for (i=0; i<l; i++) {  // link all TreeNode objects
    node = nodeById[ data[i].index ];
    node.parent = nodeById[node.data.parent];
    node.parent.children.push(node);
  }
  return nodeById[0].sortRecursive();
}
tree.walk(function () { console.log(this.data) }, true);
这将产生:

{ index: 4, sort: 4, parent: 0} { index: 2, sort: 7, parent: 0} { index: 1, sort: 10, parent: 0} { index: 5, sort: 13, parent: 1} { index: 8, sort: 6, parent: 5} { index: 7, sort: 2, parent: 8} { index: 6, sort: 20, parent: 5} { index: 3, sort: 15, parent: 1} {索引:4,排序:4,父级:0} {索引:2,排序:7,父级:0} {索引:1,排序:10,父级:0} {索引:5,排序:13,父级:1} {索引:8,排序:6,父级:5} {索引:7,排序:2,父级:8} {索引:6,排序:20,父级:5} {索引:3,排序:15,父级:1}
使用更复杂的有效负载函数来实现其他效果,例如在带有jQuery的表中添加表行或将项添加到
框中。

上面的Tomalak请求,我发布了他们答案的单例版本。这是:

/**
 * Represents sorted results in a tree structure.
 */
Tree = (function() {

    /**
     *
     * @type {Object} nodes Holds all the nodes in a flat format.
     * @type {Object} nodes.data The data that is held in this node.
     * @type {Object} nodes.parent Points to the parent object of this node.
     * @type {Array} nodes.children An array of the child nodes of this node.
     */
    var nodes = {};

    /**
     * @type {Object} root_node A Reference to the root node in nodes.
     */
    var root_node;

    /**
     * A sort function to sort the nodes by the data.sort value in each node.
     * @param {Number} a The first node to compare
     * @param {Number} b The second node to compare
     * @return {Boolean} Swap these nodes or not.
     */
    var comparer = function (a, b) {
        return a.data.sort < b.data.sort ? 0 : 1;
    };

    /**
     * Sorts all the nodes so that they are in the correct order according to each nodes data.sort value.
     * @param {Object} node A reference to the node in the nodes object.
     */
    var sortRecursive = function (node) {
        node.children.sort(comparer);
        var len = node.children.length;
        for (var i = 0 ; i < len ; i++) {
            sortRecursive(node.children[i]);
        }
    };

    /**
     * Create a new node with the passed in data.
     * @param {Object} data The data that is associated with this node.
     */
    var create_node = function(data){
        var node = {
            data : data,
            parent : null,
            children : []
        };
        return node;
    };

    return {

        /**
         * Create a new tree of data
         * @param {Array} data An array of data objects to transorm into a tree.
         * @param {Array} data[].index The id of this node
         * @param {Array} data[].parent The parent id of this node.
         * @param {Number} root_id Id of the root node.
         */
        create : function(data, root_id){

            // Clear any previous data
            nodes = {};

            var i;
            var len = data.length;

            // Create an empty root node
            nodes[root_id] = create_node({});
            root_node = nodes[root_id];

            // Make node objects for each data item
            for (i=0; i<len; i++) {
                if(typeof data[i].sort !== "undefined")
                    nodes[ data[i].index ] = create_node(data[i]);
            }

            // Link all TreeNode objects
            for (i=0; i<len; i++) {
                var node = nodes[data[i].index];
                node.parent = nodes[node.data.parent];
                node.parent.children.push(node);
            }
            sortRecursive(nodes[root_id]);
        },

        /**
         * Walk through the nodes in nested and then sorted order, calling the passed in callback for each node.
         * @param {Function} callback A callback function to call for each node.
         * @param {Boolean} recursive Should the walkback be recursive, or just fetch the top level results.
         * @param {Object|Undefined} node The node that is currently being walked.
         *                                Ommit this value and the root node will be used.
         */
        walk : function(callback, recursive, node) {
            if(typeof node == "undefined")
                node = root_node;

            for (var i = 0, len = node.children.length; i < len; i++) {
                var child = node.children[i];
                callback.apply(child, Array.prototype.slice.call(arguments, 2));
                if (recursive)
                    arguments.callee(callback, recursive, child);
            }
        }

    };
})();
使用以下命令获取已排序的数组:

var sorted = [];
Tree.walk(function(){
    sorted.push(this.data);
}, true);

这个算法给我的结果和我的完全一样。这与您在问题中要求的不同。谢谢Tomalak,这是一个很好的OOJavaScript。也比我的效率高。这也是递归的一个很好的例子。@SystemicPlumble:谢谢。还可以看到几分钟前添加的功能。再次感谢。我决定做基准测试。你的答案比我的快250倍。出于好奇,我随后将你的答案转换为单例闭包,并获得了进一步的10%。不知道为什么。它只能处理一棵树,因为它是一个单体,但对于我的用例来说,这很好。很好!如果你能把这些代码作为你自己的答案发布,我想看看。我已经在下面发布了。为了反映本文中的示例数据,我更改了一些变量名。希望不会破坏任何东西。+1用于分享您的解决方案。仅供参考。
arguments.callee
已被弃用。感谢您对arguments.callee的介绍
Tree.create(unsorted_data, parent_id);
var sorted = [];
Tree.walk(function(){
    sorted.push(this.data);
}, true);