web-dev-qa-db-ja.com

さまざまなブラウザーでのArray.sort()メソッドの安定性はどのくらいですか?

ECMA Scriptの仕様では、配列の並べ替えに使用するアルゴリズムを指定しておらず、並べ替えを安定させるかどうかも指定していないことを知っています。

Firefoxのこの情報 が見つかりました。これは、firefoxが安定したソートを使用することを指定します。

IE 6/7/8、Chrome and Safari?

61
Boushley

ES2019現在、安定するには sort が必要です。 ES2018までのECMAScript第1版では、不安定になることが許可されていました。

単純なテストケース (見出しを無視します。エンジンのソートが安定している場合、2番目の数値セットは連続している必要があります)。注:このテストケースは、Chrome(技術的には、V8の))の一部のバージョンでは機能しません。配列が大きくなると不安定になります( Details 。)動作をトリガーするのに十分な大きさに配列を変更する修正版については、質問の最後を参照してください。

IEの並べ替えは、私がこれまで使用してきた限り(つまりIE6)安定しています。 IE8でもう一度確認すると、まだ問題があるようです。

また、リンク先のMozillaページにはFirefoxの種類が安定していると書かれていますが、Firefox 2.0より前(およびそれを含む)には必ずしもそうではなかったと断言します。

いくつかの大雑把な結果:

  • IE6 +:stable
  • Firefox <3:不安定
  • Firefox> = 3:stable
  • Chrome <70:不安定
  • Chrome> = 70:stable
  • Opera <10:不安定
  • Opera> = 10:stable
  • Safari 4:stable
  • エッジ:長い配列では不安定( > 512 elements

Windowsでのすべてのテスト。

以下も参照してください:javascriptでの高速で安定したソートアルゴリズムの実装

このテストケース( here から変更)は、V8の問題を示します(たとえば、Node v6、Chrome <v70) 「より効率的な」ソート方法を選択するのに十分なエントリを配列に確保することにより、これは非常に古いJavaScriptエンジンを念頭に置いて書かれているため、最新の機能はありません。

function Pair(_x, _y) {
    this.x = _x;
    this.y = _y;
}
function pairSort(a, b) {
    return a.x - b.x;
}
var y = 0;
var check = [];
while (check.length < 100) {
    check.Push(new Pair(Math.floor(Math.random() * 3) + 1, ++y));
}
check.sort(pairSort);
var min = {};
var issues = 0;
for (var i = 0; i < check.length; ++i) {
    var entry = check[i];
    var found = min[entry.x];
    if (found) {
        if (found.y > entry.y) {
            console.log("Unstable at " + found.i + ": " + found.y + " > " + entry.y);
            ++issues;
        }
    } else {
        min[entry.x] = {x: entry.x, y: entry.y, i: i};
    }
}
if (!issues) {
    console.log("Sort appears to be stable");
}
60
Crescent Fresh

qsort()のためにC/C++で日常的に使用しているトリックを共有したいと思います。

JSのsort()では、比較関数を指定できます。同じ長さの2番目の配列を作成し、0から増加する数値で埋めます。

function stableSorted(array, compareFunction) {
  compareFunction = compareFunction || defaultCompare;
  var indicies = new Array(array.length);
  for (var i = 0; i < indicies.length; i++)
    indicies[i] = i;

これは、元の配列へのインデックスです。 2番目の配列をソートします。カスタム比較関数を作成します。

  indicies.sort(function(a, b)) {

2番目の配列から2つの要素を取得します。これらを元の配列のインデックスとして使用し、要素を比較します。

    var aValue = array[a], bValue = array[b];
    var order = compareFunction(a, b);
    if (order != 0)
      return order;

要素が等しい場合は、インデックスを比較して順序を安定させます。

   if (a < b)
     return -1;
   else
     return 1;
  });

Sort()の後、2番目の配列には、安定したソート順序で元の配列の要素にアクセスするために使用できるインデックスが含まれます。

  var sorted = new Array(array.length);
  for (var i = 0; i < sorted.length; i++)
    sorted[i] = array[indicies[i]];
  return sorted;
}

// The default comparison logic used by Array.sort(), if compareFunction is not provided:
function defaultCompare(a, b) {
  a = String(a);
  b = String(b);
  if (a < b) return -1;
  else if (a > b) return 1;
  else return 0;
}

一般に、安定したソートアルゴリズムは成熟しているだけで、優れたol 'qsortと比較してより多くの追加メモリが必要です。だからこそ、安定したソートを要求する仕様はほとんどありません。

14
Dummy00001

V8 v7.0およびChrome 70の時点で、Array.prototype.sort実装は安定しています。

以前は、V8は 10を超える要素 の配列に対して不安定なQuickSortを使用していました。現在、V8は安定したTimSortアルゴリズムを使用しています。

不安定なArray#sort実装がまだ残っている唯一の主要なエンジンJavaScriptエンジンは、Microsoft Edgeで使用されているChakraです。 Chakraは、 512を超える要素 の配列にQuickSortを使用します。より小さな配列の場合、安定した挿入ソートの実装を使用します。

デモ:https://mathiasbynens.be/demo/sort-stability

5
Mathias Bynens