示例对象数组:
[{
id: 'a',
beforeId: null
}, {
id: 'b',
beforeId: 'c'
}, {
id: 'c',
beforeId: 'a'
}, {
id: 'd',
beforeId: 'b'
}]
输出顺序:d-b-c-a
;每个元素根据其beforeId
属性相对于每个其他元素进行排序。
我可以创建一个临时数组并对上面的数组进行排序。可以使用array.sort
进行排序吗?
答案 0 :(得分:7)
您可以使用关系构建一个对象,并使用beforeId: null
对象生成结果,并取消结果数组的所有对象。
下一个对象是实际val
作为键的对象。
复杂性:O(2n)。
function chain(array) {
var o = {}, pointer = null, result = [];
array.forEach(a => o[a.beforeId] = a);
while (o[pointer]) {
result.unshift(o[pointer]);
pointer = o[pointer].val;
}
return result;
}
var data = [{ val: 'a', beforeId: null }, { val: 'b', beforeId: 'c' }, { val: 'c', beforeId: 'a' }, { val: 'd', beforeId: 'b' }];
console.log(chain(data));

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

答案 1 :(得分:4)
这是一种非常低效且天真的算法,但它有效:
const array = [
{id: 'a', beforeId: null},
{id: 'b', beforeId: 'c'},
{id: 'c', beforeId: 'a'},
{id: 'd', beforeId: 'b'}
];
// find the last element
const result = [array.find(i => i.beforeId === null)];
while (result.length < array.length) {
// find the element before the first element and prepend it
result.unshift(array.find(i => i.beforeId == result[0].id));
}
console.log(result);
答案 2 :(得分:1)
是否可以使用array.sort进行排序?
确定,有辅助功能:
graph = [
{id: 'a', beforeId: null},
{id: 'b', beforeId: 'c'},
{id: 'c', beforeId: 'a'},
{id: 'd', beforeId: 'b'}
];
let isBefore = (x, y) => {
for (let {id, beforeId} of graph) {
if (id === x)
return (beforeId === y) || isBefore(beforeId, y);
}
return false;
};
graph.sort((x, y) => x === y ? 0 : (isBefore(x.id, y.id) ? -1 : +1))
console.log(graph);
如果
isBefore
在x
之前立即或传递,则 y
会返回true。
对于通用的非线性拓扑排序,请参阅https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
UPD:正如here所示,结果证明效率非常低,因为sort
涉及许多不必要的比较。这是迄今为止最快的(迄今为止)版本:
function sort(array) {
let o = {}, res = [], len = array.length;
for (let i = 0; i < len; i++)
o[array[i].beforeId] = array[i];
for (let i = len - 1, p = null; i >= 0; i--) {
res[i] = o[p];
p = o[p].id;
}
return res;
}
这是@Nina的想法,针对速度进行了优化。
答案 3 :(得分:0)
您可以尝试这种方法:
// order(null, vals, []) = ["d", "b", "c", "a"]
function order(beforeId, vals, result){
var id = beforeId || null;
var before = vals.filter(function(val){
return val.beforeId === id
});
if (before.length === 0) return result;
return order(before[0].val,
vals,
[before[0].val].concat(result));
}