Javascript 如何对有时具有不可比较值的数组进行排序?
我试图对有时彼此无法比较的值进行排序。我正在排序的数据类似于一棵树Javascript 如何对有时具有不可比较值的数组进行排序?,javascript,node.js,sorting,Javascript,Node.js,Sorting,我试图对有时彼此无法比较的值进行排序。我正在排序的数据类似于一棵树 1. if a depends on b, then a should be sorted after b 2. if b depends on a, then b should be sorted after a 3. if neither a or b depend on each other then they are incomparable and no comparison can be drawn 我目前正在ja
1. if a depends on b, then a should be sorted after b
2. if b depends on a, then b should be sorted after a
3. if neither a or b depend on each other then they are incomparable and no comparison can be drawn
我目前正在javascript中使用带有自定义比较函数的函数。但我怀疑这不符合我的基本要求
带有测试的示例代码:
// k depends on nothing - but every other element depends on k, so k should come first
var k = {
uuid: 'k',
dependsOn: []
};
// z depends on k and so k must come before z
var z = {
uuid: 'z',
dependsOn: ['k']
}
// y should be go before x as x depends on y
// y also depends on k so k should go before y
var y = {
uuid: 'y',
dependsOn: ['k']
}
// x has both y and k as its dependencies
var x = {
uuid: 'x',
dependsOn: ['y', 'k']
}
function compare(a, b) {
// if they have the same uuid; then they are the same
if (a.uuid === b.uuid) {
return 0
}
// if a depends on b, then a should be after b
for (var i = 0, len = a.dependsOn.length; i < len; i++) {
var dependsOn = a.dependsOn[i];
if (dependsOn === b.uuid) {
return 1
}
}
// if b depends on a, then b should be after a
for (var i = 0, len = b.dependsOn.length; i < len; i++) {
var dependsOn = b.dependsOn[i];
if (dependsOn === a.uuid) {
return -1
}
}
// this is the edge case,
// if neither a or b depends on each other, then they don't have relative ranking
return null
}
// this is every possible permutation - they should all sort to the same orders
// expected order k, z, y, x or k, y, z, x or k, y, x, z
// because:
// k -> z as z depends on k
// k -> y as y depends on k
// no relative ranking between z and y as they don't depend on each other
// x depends on both y and k so x will come after them
var perms = [
[x, y, z, k],
[x, y, k, z],
[x, z, y, k],
[x, z, k, y],
[x, k, y, z],
[x, k, z, y],
[y, x, z, k],
[y, x, k, z],
[y, z, x, k],
[y, z, k, x],
[y, k, x, z],
[y, k, z, x],
[z, x, y, k],
[z, x, k, y],
[z, y, x, k],
[z, y, k, x],
[z, k, x, y],
[z, k, y, x],
[k, x, y, z],
[k, x, z, y],
[k, y, x, z],
[k, y, z, x],
[k, z, x, y],
[k, z, y, x],
]
var _ = require('underscore')
perms.forEach(function(perm) {
var s = perm.sort(compare)
var p = _.pluck(s, 'uuid')
console.log(p, _.isEqual(p, ['k', 'z', 'y', 'x']) || _.isEqual(p, ['k', 'y', 'z', 'x']) || _.isEqual(p, ['k', 'y', 'x', 'z']))
})
我发现了一个似乎不太积极维护的图书馆,它完成了这项工作:
如果您需要拓扑排序的行为,github的my graph js库确实有这种类型的实现: 执行顶部排序的graph algorithms库中的示例代码如下所示:
var jsgraphs=require('js-graph-algorithms')
A可与返回-ve、+ve或0值的排序一起使用,以创建所需的顺序。“不可比较”的情况是0,或者本质上是a==b。我确实提供了一个比较函数。如果我在不可比较的情况下返回0,排序函数会认为它们相等(这与不可比较不同),并且会返回不正确的结果是的,您需要拓扑排序。既然您现在知道了这个术语,您应该能够在web()上找到js实现。或者只是实现WP文章中列出的算法。如果您需要进一步的帮助,请让我们知道;如果你编写一个解决方案。谢谢Bergi,当我问这个问题时,我还不知道拓扑排序。
[ 'k', 'y', 'x', 'z' ] true
[ 'k', 'y', 'x', 'z' ] true
[ 'k', 'x', 'z', 'y' ] false \\ x depends on k and y so it should be after y
[ 'k', 'x', 'z', 'y' ] false
[ 'k', 'y', 'x', 'z' ] true
[ 'k', 'x', 'z', 'y' ] false \\ x depends on k and y so it should be after y
[ 'k', 'y', 'x', 'z' ] true
[ 'k', 'y', 'x', 'z' ] true
[ 'k', 'y', 'z', 'x' ] true
[ 'k', 'y', 'z', 'x' ] true
[ 'k', 'y', 'x', 'z' ] true
[ 'k', 'y', 'z', 'x' ] true
[ 'k', 'z', 'y', 'x' ] true
[ 'k', 'z', 'y', 'x' ] true
[ 'k', 'z', 'y', 'x' ] true
[ 'k', 'z', 'y', 'x' ] true
[ 'k', 'z', 'y', 'x' ] true
[ 'k', 'z', 'y', 'x' ] true
[ 'k', 'y', 'x', 'z' ] true
[ 'k', 'x', 'z', 'y' ] false \\ x depends on k and y so it should be after y
[ 'k', 'y', 'x', 'z' ] true
[ 'k', 'y', 'z', 'x' ] true
[ 'k', 'z', 'y', 'x' ] true
[ 'k', 'z', 'y', 'x' ] true
// k depends on nothing - but every other element depends on k, so k should come first
var k = {
uuid: 'k',
dependsOn: []
};
// z depends on k and so k must come before z
var z = {
uuid: 'z',
dependsOn: ['k']
}
// y should be go before x as x depends on y
// y also depends on k so k should go before y
var y = {
uuid: 'y',
dependsOn: ['k']
}
// x has both y and k as its dependencies
var x = {
uuid: 'x',
dependsOn: ['y', 'k']
};
function Edges(array) {
var edges = []
for (var k in array) {
var node = array[k]
node.dependsOn.forEach(function(dependency) {
edges.push([dependency].concat(node.uuid))
})
}
return edges
}
// this is every possible permutation - they should all sort to the same orders
// expected order k, z, y, x or k, y, z, x or k, y, x, z
// because:
// k -> z as z depends on k
// k -> y as y depends on k
// no relative ranking between z and y as they don't depend on each other
// x depends on both y and k so x will come after them
var perms = [
[x, y, z, k],
[x, y, k, z],
[x, z, y, k],
[x, z, k, y],
[x, k, y, z],
[x, k, z, y],
[y, x, z, k],
[y, x, k, z],
[y, z, x, k],
[y, z, k, x],
[y, k, x, z],
[y, k, z, x],
[z, x, y, k],
[z, x, k, y],
[z, y, x, k],
[z, y, k, x],
[z, k, x, y],
[z, k, y, x],
[k, x, y, z],
[k, x, z, y],
[k, y, x, z],
[k, y, z, x],
[k, z, x, y],
[k, z, y, x],
]
var _ = require('underscore')
var toposort = require('toposort')
perms.forEach(function(perm) {
var p = toposort(Edges(perm));
console.log(p, _.isEqual(p, ['k', 'z', 'y', 'x']) || _.isEqual(p, ['k', 'y', 'z', 'x']) || _.isEqual(p, ['k', 'y', 'x', 'z']))
})
var dag = new jsgraphs.DiGraph(7);
dag.addEdge(0, 5); // edge point from vertex 0 to 5
dag.addEdge(0, 2);
dag.addEdge(0, 1);
dag.addEdge(3, 6);
dag.addEdge(3, 5);
dag.addEdge(3, 4);
dag.addEdge(5, 4);
dag.addEdge(6, 4);
dag.addEdge(6, 0);
dag.addEdge(3, 2);
dag.addEdge(1, 4);
var ts = new jsgraphs.TopologicalSort(dag);
var order = ts.order();
console.log(order); // display array which is the topological sort order