JavaScript
Chrome
v8
InternetExplorer

【JavaScript】同じ値が正しくソートされない【Chrome】

概要

業務で数百件のデータをソートした時、IEとChromeによって結果が異なっていたので原因をメモ。

現象

ChromeでArray.prototype.sort()を実施したとき、同じ値の順番が変更されていた。

原因

・v8エンジン詰んでるChromeは、要素数によってソートロジックが変わる。

参照:http://kakts-tec.hatenablog.com/entry/2016/12/18/153845

具体的には要素数が10より大きい値をソートする場合は、クイックソートを実行している。jsfiddle

let array = [
    {'number': 1, 'value': 1},
    {'number': 2, 'value': 1},
    {'number': 3, 'value': 1},
    {'number': 4, 'value': 1},
    {'number': 5, 'value': 1},
    {'number': 6, 'value': 1},
    {'number': 7, 'value': 1},
    {'number': 8, 'value': 1},
    {'number': 9, 'value': 1},
    {'number': 10, 'value': 1},
    {'number': 11, 'value': 1}
];

// ソート対象の要素数が10より大きければ、v8エンジンはクイックソートを行う
array.sort((a,b) => {
    return a.value > b.value ? 1 : -1; 
});

console.log(array);

クイックソートは安定ソートではないので、順序が担保されないらしい・・・
今回はIE対応のみなので、無視でよかった・・・
Chromeで同値の順序を担保するなら、
別の配列に順序を別のプロパティとして保存 → 同値なら順序を考慮してソートを実施。jsfiddle

let array = [
    {'number': 1, 'value': 1},
    {'number': 2, 'value': 1},
    {'number': 3, 'value': 1},
    {'number': 4, 'value': 1},
    {'number': 5, 'value': 1},
    {'number': 6, 'value': 1},
    {'number': 7, 'value': 1},
    {'number': 8, 'value': 1},
    {'number': 9, 'value': 1},
    {'number': 10, 'value': 1},
    {'number': 11, 'value': 1}
];

// ソート対象の要素数が10より大きければ、v8エンジンはクイックソートを行う
array.sort((a,b) => {
    // 同値なら格納した順番を考慮
  if (a.value === b.value) {
        return a.number > b.number ? 1 : -1; 
    }
    return a.value > b.value ? 1 : -1; 
});

console.log(array);