如何订购以下列表以确保子项目始终以其父项目开头?列表中的某些项目既不是子项目也不是父项目,它们应该按字母顺序与其他父级项目一起排序。
所需的输出顺序看起来像这样
[ fizz, foobar, foobar xland, the shire, frogmorton, hobbiton]
以下是我到目前为止所尝试过的代码片段,我非常肯定将代码链接在一起是一个很好的方法,因为代码可读性原因,但我遇到了一些问题与排序规则背后的逻辑。
var items = [
{
"_id": "Fizz"
},
{
"_id": "Frogmorton",
"parent": "The Shire"
},
{
"_id": "Hobbiton",
"parent": "The Shire"
},
{
"_id": "Foobar",
"isParent": true
},
{
"_id": "Foobar Xland",
"parent": "Foobar"
},
{
"_id": "The Shire",
"isParent": true
}
]
var sortedArray = items
.sort(function(first, second) {
if(first.isParent && !second.isParent) {
return -1
}
else if(second.isParent && first._id != second.parent) {
return 0
} else {
return 1
}
})
console.log("sortedArray", sortedArray)

答案 0 :(得分:2)
此解决方案适用于任何深度,并使用树以正确的顺序获取相关项目。
var items = [{ _id: "Fizz" }, { _id: "Frogmorton", parent: "The Shire" }, { _id: "Hobbiton", parent: "The Shire" }, { _id: "Foobar", isParent: true }, { _id: "Foobar Xland", parent: "Foobar" }, { _id: "The Shire", isParent: true }],
tree = function (data, root) {
var r = [], o = {};
data.forEach(function (t) {
var a = { i: t._id, parent: t.p, data: t };
a.children = o[a.i] && o[a.i].children;
o[a.i] = a;
if (a.p === root) {
r.push(a);
} else {
o[a.p] = o[a.p] || {};
o[a.p].children = o[a.p].children || [];
o[a.p].children.push(a);
}
});
return r;
}(items.sort(function (a, b) { return a._id.localeCompare(b._id); }), undefined),
ordered = tree.reduce(function flat(r, o) {
return r.concat(o.data, (o.children || []).reduce(flat, []));
}, []);
console.log(ordered);

.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:2)
你可以使用这个函数,它可以处理grand-grand-grand -...- children,通过将它转换为临时树并在其中执行深度优先迭代 - 所有功能都是:< / p>
function depthFirst(items) {
return Array.from(items.reduce( (mp, o) =>
(mp.get(o.parent).children.push(mp.get(o._id)), mp),
new Map([{}].concat(items).map( (o) => [o._id, { children: [], orig: o }] ))
), ([_, o]) =>
(o.children.sort((a, b) => a.orig._id.localeCompare(b.orig._id)), o)
)[0].children.reduce(function collect(acc, o) {
return acc.concat(o.orig, o.children.reduce(collect, []))
}, []);
}
// Sample input
var items = [{
"_id": "Frogmorton",
"parent": "The Shire"
}, {
"_id": "Hobbiton",
"parent": "The Shire"
}, {
"_id": "Foobar",
}, {
"_id": "Foobar Xland",
"parent": "Foobar"
}, {
"_id": "Fizz"
}, {
"_id": "The Shire"
}, {
"_id": "added grandchild",
"parent": "Frogmorton"
}];
console.log(depthFirst(items));
答案 2 :(得分:1)
以下解决方案可行
var items = [
{
"_id": "Frogmorton",
"parent": "The Shire"
},
{
"_id": "Hobbiton",
"parent": "The Shire"
},
{
"_id": "Foobar",
"isParent": true
},
{
"_id": "Foobar Xland",
"parent": "Foobar"
},
{
"_id": "Fizz"
},
{
"_id": "The Shire",
"isParent": true
}
]
const sortedArray = items
.filter(item => item.isParent || !item.parent)
.sort((a, b) => a._id.localeCompare(b._id))
.map(parent => [parent].concat(
items
.filter(item => item.parent === parent._id)
.sort((a, b) => a._id.localeCompare(b._id)))
)
.reduce((acc, item) => acc.concat(item), [])
console.log(sortedArray);
答案 3 :(得分:0)
你可以使用带有散列的闭包来拥有一个独立的方法。
const items = [ { _id: "Frogmorton", parent: "The Shire" }, { _id: "Hobbiton", parent: "The Shire" }, { _id: "Foobar", isParent: true }, { _id: "Foobar Xland", parent: "Foobar" },{ _id: "Fizz" }, { _id: "The Shire", isParent: true }],
result = Object.entries(items.slice().reduce((c => (a, b) =>
(c['val'] = b.parent || b._id, c['parent'] = b.parent, !a[c.val] ?
a[c.val] = [b] :
c.parent ? a[c.val].push(b) :
a[c.val].unshift(b), a)
)({}), ({}))).sort((a, b) =>
a[0].localeCompare(b[0])).map(x =>
x[1]).reduce((x, i) => x.concat(i), []);
console.log(result);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;