意外と知られていないJavaScriptのsort()の使用方法

sort() とは

配列の要素を並び替え(ソート)するためのもの。

例えば [2, 1, 3].sort() なら [1, 2, 3] となり、['b', 'a', 'c'].sort() なら['a', 'b', 'c'] となる。

var arr = [2, 1, 3];
var result = arr.sort();
console.log(result);
// => [1, 2, 3]

var arr = ['b', 'a', 'c'];
var result = arr.sort();
console.log(result);
// => ['a', 'b', 'c']

[3, 1, 10].sort() は昇順ではない

[3, 1, 10].sort() は [1, 3, 10] ではなく [1, 10, 3] となる。初心者がJavaScriptを使用する際によく間違えやすい。

なぜ [1, 10, 3] になるかというと、sort()だと数値ではなく文字列として並び替えるからだ。

この場合は下記のように書くのが正しい。

a - bを返して低い数値ほど配列の最初の方に入るようにする。(降順はabが逆になる)

var arr = [1, 10, 3];
var result = arr.sort((a, b) => a - b);
console.log(result);
// => [1, 3, 10]

var arr = [1, 10, 3];
var result = arr.sort((a, b) => b - a);
console.log(result);
// => [10, 3, 1]

['a', 'A', 'B'].sort() について

['b', 'a', 'c'].sort()が ['a', 'b', 'c'] なので ['a', 'A', 'B'].sort() の結果は変わらないだろうと思う人もいるかもしれないが結果は ['A', 'B', 'a'] となる。

大文字・小文字のアルファベットは大文字がより低いとみなされる。

var arr = ['a', 'A', 'B'];
var result = arr.sort();
console.log(result);
// => ['A', 'B', 'a']

もしも大文字・小文字に関わらず、BよりもA(a)を左に表示して ['a', 'A', 'B'] としたい場合は下記のようになる。

var arr = ['a', 'B', 'A'];
var result = arr.sort((a, b) => {
  return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
});
console.log(result);
// =>  ['a', 'A', 'B']

文字列の長さで並び替え

lengthを使用して下記のように書けば文字列の長さで並び替えできる。

var arr = ['apple', 'banana', 'cake'];
var result = arr.sort((a, b) => a.length - b.length);
console.log(result);
// => ["cake", "apple", "banana"]

日付順で並び替え

new Date()を使用して下記のように書けば文字列の長さで並び替えできる。

var arr = ['3/14', '1/16', '2/14'];
var result = arr.sort((a, b) => new Date(a) - new Date(b));
console.log(result);
// => ["1/16", "2/14", "3/14"]

リテラル文字列をsort()で並び替え

例えば '2413' という文字列があったとしても '2413'.sort() で '1234' に並び替えることはできない。sort()は配列のみに使用可能だからである。

しかし、文字列を配列に変換してsort()を使用したあとに文字列に戻すという手順であれば並び替えることは可能だ。

var str = '2413';
var result = str.split('').sort().join('');
console.log(result);
// => '1234'

配列オブジェクトを並び替え

配列オブジェクトは「配列」なので並び替えの基準となるキーを指定すれば並び替えが可能だ。

var arr = [
  {name: 'apple', price: 200},
  {name: 'banana', price: 300},
  {name: 'cookie', price: 100}
];
var result = arr.sort((a, b) => a.price - b.price);
console.log(result);
// [
//   {name: 'cookie', price: 100},
//   {name: 'apple', price: 200},
//   {name: 'banana', price: 300}
// ];

破壊ソートと非破壊ソート

sort()を使用しただけではソート前の変数に値をpushするとソート後にも反映されてしまう。(破壊ソート)

これを防ぐためにはslice()を併用する。(非破壊ソート)

// 破壊ソート
var arr = [3, 1, 2];
var result = arr.sort();
console.log(result);
// => [1, 2, 3]

arr.push(777);
console.log(result);
// => [1, 2, 3, 777]

// 非破壊ソート
var arr = [3, 1, 2];
var result = arr.slice().sort();
console.log(result);
// => [1, 2, 3]

arr.push(777);
console.log(result);
// => [1, 2, 3]

漢字もsort()で並べ替えできる

日本人だと漢字を並び替えたいことがある。例えば漢数字の壱弐参や曜日の月〜日などだ。

このようなのでも配列でルールを作成して下記のように優劣をつければ漢字も並び替えることができる。
(応用すればSun, Mon, Tueも可能)

var days = ['火', '日', '月'];
var daysOrder = ['月', '火', '水', '木', '金', '土', '日'];
var result = days.sort((x, y) => {
  return daysOrder.indexOf(x) - daysOrder.indexOf(y);
});
console.log(result);
// => ['月', '火', '日']

二次元配列のsortする方法

二次元配列を並び替えたい場合は下記の通り。[1]があるとは限らないので[0]で並び替えることが多い。

var arr = [[3, 1], [1, 6], [2, 4]];
var result = arr.sort((a, b) => a[0] - b[0]);
console.log(result);
// => [[1, 6], [2, 4], [3, 1]]

重複を除外してsortする方法

sort前にfilterを使用する。

var arr = [3, 1, 2, 2, 1, 1];
var result = arr
  .filter((v, i, s) => s.indexOf(v) === i)
  .sort((a, b) => a - b);
console.log(result);
// => [1, 2, 3]