我有一组嵌套对象:
[
{_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
的增长呈指数级增长,所以我想知道我是否可以采取措施来改进这一点。
答案 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"}