10011


Mac版Chrome(42.0.2311.135 64-bit)で、  
自前の比較関数を用いて文字列配列のソートをすると変な結果になります。

以下から試せます。

[code]

    var arr1 = ["hoge0", "piyo0", "fuga0", "fuga1", "fuga2", "fuga3", "fuga5", "fuga6", "fuga7", "fuga8"];
    var arr2 = ["hoge0", "piyo0", "fuga0", "fuga1", "fuga2", "fuga3", "fuga5", "fuga6", "fuga7", "fuga8", "fuga9"];
    var compare = function(a, b){
      return a > b;
    };
    
    document.body.innerHTML += '1) ' + arr1.sort(compare).join(',') + '<br>';
    document.body.innerHTML += '2) ' + arr2.sort(compare).join(',') + '<br>';
    document.body.innerHTML += '3) ' + arr2.sort().join(',');
[/code]

Firefoxなら2)と3)が同じ結果になるのですが、  
Chromeで実際に実行すると以下の結果になります。2)が変です。

[code]

    1) fuga0,fuga1,fuga2,fuga3,fuga5,fuga6,fuga7,fuga8,hoge0,piyo0
    2) fuga3,fuga9,fuga0,fuga1,fuga2,fuga8,fuga5,fuga6,fuga7,hoge0,piyo0
    3) fuga0,fuga1,fuga2,fuga3,fuga5,fuga6,fuga7,fuga8,fuga9,hoge0,piyo0
    
[/code]

これはバグなのでしょうか？それともソートの仕方が間違っているのでしょうか？


CC BY-SA 3.0
2015-05-10T11:50:34.133
10008
2019-12-13T14:07:13.707
2244
question
javascript google-chrome
Chromeでの文字列配列ソートがおかしい


比較関数には

[code]

    １つ目の引数が２つ目の引数よりも小さい場合は、負の値を返す。
    ２つの引数が等しい場合は０を返す。
    １つ目の引数が２つ目の引数よりも大きい場合は、正の値を返す。
    
[/code]

必要があります。  
なので、示された比較関数は正確にはこの条件を満たしていません。  
例えば、以下のようにする必要があります。  
`var compare = function(a,b){ return (a > b) - (a < b); };`


CC BY-SA 3.0
2015-05-10T12:02:23.277
10011
2015-05-10T12:02:23.277
5044
10008
answer


比較関数の戻り値については既出の通りです。

しかし、オブジェクトのソートを行う場合で、各種ブラウザ間でソート結果を同じにしたい場合は、 **0を返さないようにする**
必要があります。Chromeのソートは（配列の要素数によっては）安定ソートになりません。

要するに、比較関数が `return 0` した場合、ブラウザによっては並び替えたり、並び替えなかったりするということです。

以下のスニペットを実行すると、ソート結果の違いが分かります。

[code]

    function unstableSort(a, b) {
      return a.x - b.x;
    }
    
    function stableSort(a, b) {
      if (a.x === b.x) {
        return indexed.indexOf(a) - indexed.indexOf(b);
      }
    
      return unstableSort.call(this, a, b);
    }
    
    function display(title, items) {
      var div = $('<div />'),
        ol = $('<ol />');
    
      div.append('<h1>' + title + '</h1>').append(ol);
    
      items.forEach(function(item, index) {
        ol.append('<li>(' + item.x + ', ' + item.y + ')</li>');
      });
    
      $('body').append(div);
    }
    
    var items = [{
          x: 1,
          y: 1
        }, {
          x: 1,
          y: 2
        }, {
          x: 1,
          y: 3
        }, {
          x: 1,
          y: 4
        },
        {
          x: 1,
          y: 5
        }, {
          x: 1,
          y: 6
        }, {
          x: 1,
          y: 7
        }, {
          x: 1,
          y: 8
        },
        {
          x: 1,
          y: 9
        }, {
          x: 1,
          y: 10
        }, {
          x: 1,
          y: 11
        }
      ],
      indexed = items.slice(0);
    
    items.sort(unstableSort);
    display('Unstable', items);
    
    items.sort(stableSort);
    display('Stable', items);
[/code]

[code]

    body>div {
      width: 49%;
      display: inline-block;
    }
[/code]

[code]

    <p><em>This demo is designed to be run in Chrome -- the latest version of FireFox (as at 02/07/2014) and IE10 both implement stable sorting, at least for an array of the size used here.  Chrome's (v35) sort is stable for an array of up to 10 elements as it uses the Insertion Sort algorithm (which is stable); for arrays of greater than 10 elements, it uses a non-stable version of the QuickSort algorithm.</em></p>
[/code]


CC BY-SA 4.0
2015-05-11T06:37:34.743
10031
2019-12-13T14:07:13.707
2019-12-13T14:07:13.707
32986
9608
10008
answer