为什么我的Javascript程序中的Array.sort()方法不稳定?

时间:2016-07-18 19:46:21

标签: javascript arrays sorting

这是我的jsFiddle:

//Change this variable to change the number of players sorted
var numberOfPlayers = 15;

var teams = [];
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

for(var a=0; a<numberOfPlayers; a++){
  updateStandings();
    teams.push(new Team(alphabet.charAt(a)));
}

console.log("Teams:");
for(var x=0; x<teams.length; x++){
    console.log(teams[x].name);
}

//Functions and such
function updateStandings(){
  teams.sort(function(a, b) { 
    if(a.score == b.score){ 
      if(a.tiebreak == b.tiebreak){
        return teams.indexOf(a)-teams.indexOf(b);
      }else{
        return b.tiebreak-a.tiebreak;
      }
    }else{
      return b.score-a.score;
    }
  });
}

function Team(name){
  this.name = name;
  this.score = 0;
  this.tiebreak = 0;
}

我认为问题是javascript排序不稳定,并且改变了我的比较功能,但它仍然不起作用。

3 个答案:

答案 0 :(得分:2)

JS中稳定排序的一般方法如下:

function stable_sort(array, sortfunc) {
  function _sortfunc(a, b) { return sortfunc(array[a], array[b]) || a - b; }

  return array.map((e, i) => i) . sort(_sortfunc) . map(i => array[i]);
}

这实际上做的是对索引列表进行排序。然后它将排序的索引列表映射回原始数组。重写sort函数以比较那些索引处数组中的值,如果它们相等则返回到索引本身的比较。

这种方法避免了代码中的问题,即它正在对正在排序的中间的数组进行indexOf查找。

This question可以提供信息。

答案 1 :(得分:1)

根据文档,sort方法不需要稳定:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort在某些浏览器中它是稳定的,有些则不稳定。

您需要更改比较功能,但不能以您尝试的方式更改。原因是你比较

return teams.indexOf(a)-teams.indexOf(b);
当前数组中的

。这意味着如果a和b的顺序在前面的步骤中发生了变化,那么排序例程将保留这个新顺序,而不是这些元素在开头的顺序。

有不同的解决方法。例如,您可以在排序之前创建数组的副本,并在此副本上执行indexOf。它将保留元素在排序开始之前的顺序。

但如果您事先知道订单,您也可以使用这些知识。例如,如果在排序之前团队按名称排序,您可以将名称比较为字符串而不是数组中的位置,它将比第一个选项更有效。

答案 2 :(得分:0)

因为JS&#39;排序通常是不稳定的。来自§22.1.3.24 of the spec

  

此数组的元素已排序。排序不一定稳定(即,比较相等的元素不一定保持原始顺序)。

您的团队除了名称外都创建了相同的属性,因此实际执行排序的行是:

return teams.indexOf(a)-teams.indexOf(b);

因为您正在调用indexOf,所以它会在每次重复排序时搜索项目(及其索引)。排序会改变数组(from MDN:它&#34;对数组的元素进行排序并返回数组&#34;)。

您正在搜索正在排序的同一数组中的项目,因此索引可能会在每次迭代时更改。正确地完成(相对而言),你可以用它做出永无止境的排序。

例如:

&#13;
&#13;
const data = [1, 3, 2, 4];
let reps = 0;

data.sort((a, b) => {
  console.log(data);
  
  const ia = data.indexOf(a), ib = data.indexOf(b);
  if (ia === ib || reps > 50) {
    return 0;
  } else if (ia < ib) {
    return 1;
  } else if (ib < ia) {
    return -1;
  }    
});
&#13;
&#13;
&#13;