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