按层次结构和名称对层次结构对象进行排序

时间:2016-02-11 02:15:32

标签: javascript arrays algorithm sorting quicksort

我有一组嵌套对象:

[
    {_id:1, parent:0, name:'Z'},
    {_id:4, parent:0, name:'A'},
    {_id:2, parent:1, name:'H'},    
    {_id:8, parent:2, name:'G'},        
    {_id:5, parent:4, name:'M'},
    {_id:6, parent:4, name:'N'},
    {_id:3, parent:1, name:'Z'},
    {_id:7, parent:2, name:'L'}
]

我需要对它们进行排序,因为同一级别的节点将按字母顺序排序(asc / desc可配置),并且所有子节点应该在它们的父节点之后,并且它们的父节点之间的节点也按字母顺序排序。 / p>

例如,如果按asc排序,则输出应为

[ 
    { _id: 4, parent: 0, name: 'A' },
    { _id: 5, parent: 4, name: 'M' },
    { _id: 6, parent: 4, name: 'N' },
    { _id: 1, parent: 0, name: 'Z' },
    { _id: 2, parent: 1, name: 'H' },
    { _id: 8, parent: 2, name: 'G' },
    { _id: 7, parent: 2, name: 'L' },
    { _id: 3, parent: 1, name: 'Z' } 
]

在输出中,4在1之前,因为A< Z. 5和6按字母顺序排列在4和1之前。类似的情况下8和7低于2和3之前。

如果是desc,输出应为:

[ 
    { _id: 1, parent: 0, name: 'Z' },
    { _id: 3, parent: 1, name: 'Z' },
    { _id: 2, parent: 1, name: 'H' },
    { _id: 7, parent: 2, name: 'L' },
    { _id: 8, parent: 2, name: 'G' },
    { _id: 4, parent: 0, name: 'A' },
    { _id: 5, parent: 4, name: 'M' },
    { _id: 6, parent: 4, name: 'N' } 
]

我尝试实现如下功能。

function sortByHierarchyAndName(arr, sort) {
    var i = 0; 
        j = 0;
        t = 0; 
        parentFound = false; 
        x = arr.length;
        arr2 = []; 

    //Sort by parent asc first 
    arr = arr.sort(function(a, b) {
        if(a.parent < b.parent) return -1; 
        if(a.parent > b.parent) return 1; 
        return 0; 
    }); 

    for(; i < x; i += 1) {
        t = arr2.length;
        if(t === 0)  arr2.push(arr[i]);
        else if(arr[i].parent === 0) {
            for(j = 0; j < t; j += 1) {
                if(sort === -1) {
                    if(arr[i].name >= arr2[j].name) arr2.splice(j, 0, arr[i]);
                } else {
                    if(arr[i].name <= arr2[j].name) arr2.splice(j, 0, arr[i]);
                }
            }
            if(arr2.length === t) arr2.push(arr[i]);
        }
        else {
            parentFound = false;
            for(j = 0; j < t; j += 1) {
                if(arr[i].parent === arr2[j]._id) {
                    if(j === t - 1) {
                        arr2.push(arr[i]); 
                    }
                    parentFound = true; 
                } else if(arr[i].parent === arr2[j].parent) {
                    if(sort === -1) {
                        if(j === t - 1) arr2.push(arr[i]); 
                        else if(arr[i].name >= arr2[j].name) {
                            arr2.splice(j, 0, arr[i]);
                            j = t; 
                        }
                    } else {
                        if(j === t - 1) arr2.push(arr[i]); 
                        else if(arr[i].name <= arr2[j].name) {
                            arr2.splice(j, 0, arr[i]);
                            j = t; 
                        }
                    }
                } else if(arr[i].parent > arr2[j].parent && parentFound) {
                    arr2.splice(j, 0, arr[i]);
                    j = t; 
                }
            }
        }
    }
    return arr2; 
}

假设在按父asc排序长度为f(n)的数组时,array.sort()花费n的时间,我正在为实现做一些性能分析,如下所示。

  

最佳案例:f(n)+ x * n + y * sum(1到n / 2)* n

     

最坏情况:f(n)+ x * n + y * sum(1到n)* n;

     

x - 处理arr。

中任何给定元素的因素      

y - 处理arr中任何给定元素对arr2中任何元素的因素。

正如您所看到的,在这两种情况下,执行的持续时间将随着n的增长呈指数级增长,所以我想知道我是否可以采取措施来改进这一点。

2 个答案:

答案 0 :(得分:7)

你可以使用递归算法和哈希对象,我相信这个算法的性能大约需要O(n log n):

<script>

function hierarchySortFunc(a,b ) {
  return a.name > b.name;
}

function hierarhySort(hashArr, key, result) {

  if (hashArr[key] == undefined) return;
  var arr = hashArr[key].sort(hierarchySortFunc);
  for (var i=0; i<arr.length; i++) {
    result.push(arr[i]);
    hierarhySort(hashArr, arr[i]._id, result);
  }

  return result;
}

var arr = [ 
    { _id: 4, parent: 0, name: 'A' },
    { _id: 5, parent: 4, name: 'M' },
    { _id: 6, parent: 4, name: 'N' },
    { _id: 1, parent: 0, name: 'Z' },
    { _id: 2, parent: 1, name: 'H' },
    { _id: 8, parent: 2, name: 'G' },
    { _id: 7, parent: 2, name: 'L' },
    { _id: 3, parent: 1, name: 'Z' } 
]

var hashArr = {};

for (var i=0; i<arr.length; i++) {
  if (hashArr[arr[i].parent] == undefined) hashArr[arr[i].parent] = [];
  hashArr[arr[i].parent].push(arr[i]);
}

var result = hierarhySort(hashArr, 0, []);

for (var i=0; i<result.length; i++) console.log(result[i]);

</script>

结果:

{_id: 4, parent: 0, name: "A"}
{_id: 5, parent: 4, name: "M"}
{_id: 6, parent: 4, name: "N"}
{_id: 1, parent: 0, name: "Z"}
{_id: 2, parent: 1, name: "H"}
{_id: 8, parent: 2, name: "G"}
{_id: 7, parent: 2, name: "L"}
{_id: 3, parent: 1, name: "Z"}

如果您想更改排序顺序,请更改heirarchySortFunc():

function hierarchySortFunc(a,b ) {
  return a.name < b.name;
}

答案 1 :(得分:1)

组合项目名称并按字母顺序排序可能更简单。

var array = [
    {_id:1, parent:0, name:'Z'},
    {_id:4, parent:0, name:'A'},
    {_id:2, parent:1, name:'H'},    
    {_id:8, parent:2, name:'G'},        
    {_id:5, parent:4, name:'M'},
    {_id:6, parent:4, name:'N'},
    {_id:3, parent:1, name:'Z'},
    {_id:7, parent:2, name:'L'}
]

var getItemFromID = function(id) {
  return array.filter(function(item){
    return item._id === id;
  })[0]
}

var getCombinedName = function(item) {
  var parent = getItemFromID(item.parent);
  if (parent) {
    return getCombinedName(parent) + item.name;
  } else {
    return item.name;
  }
}

array.forEach(function(item){
  item.combinedName = getCombinedName(item);
})

var sortedArray = array.sort(function(a,b) {
  return a.combinedName > b.combinedName;
});

结果:

{_id: 4, parent: 0, name: "A", combinedName: "A"}
{_id: 5, parent: 4, name: "M", combinedName: "AM"}
{_id: 6, parent: 4, name: "N", combinedName: "AN"}
{_id: 1, parent: 0, name: "Z", combinedName: "Z"}
{_id: 2, parent: 1, name: "H", combinedName: "ZH"}
{_id: 8, parent: 2, name: "G", combinedName: "ZHG"}
{_id: 7, parent: 2, name: "L", combinedName: "ZHL"}
{_id: 3, parent: 1, name: "Z", combinedName: "ZZ"}