JavaScriptのsort関数の使い方を絶対わかるまで解説する

JavaScriptのsort関数の使い方を絶対わかるまで解説する JavaScript

JavaScriptで数字を並び替えしたい時があってsort関数を使う機会があったのですが、どういう原理で並び替えをしているのかイマイチよくわからなかったので調べまくりました。

一通り理解できたので僕のように「何でそうなるの?」という人の助けに少しでもなればいいかなと思って記事を書きます。役に立たなかったらごめん。

 

また、この記事では数値の並び替えで使われるコールバック関数付きのsort関数に絞って解説します(文字列のソートは比較関数を必要とせずsort()だけでソートできるので説明を割愛します)。

sort関数が並び替えをする関数ってことはみんな知ってると思うので、「何で並び替えができるの?」「どういう原理で並び替えをしているの?」といったことを見ていきます。ぜひ時間を書けてじっくり読むことをおすすめします。

 

スポンサーリンク

sort関数で数値の順番で並び替えができる原理

まずは以下のサンプルを見てください。このサンプルは配列の中の数字を小さい順に並び替えます。

var numbers = [2, 5, 100, 4];

numbers.sort(function (a, b) {
  if (a < b) {
    return -1;
  } else if (a > b) {
    return 1;
  } else {
    return 0;
  }
});

console.log(numbers); // 結果:[2, 4, 5, 100]

こんな感じのコードはいろんな記事で紹介されていますが、僕は最初これを見た時にわからないことがいくつもありました。

  • 引数にあるa, bって何?
  • if文のa < bとかa > bって何を比較しているの?
  • return -1とかreturn 1って何?

まずはこのあたりを見ていきます。

 

引数にあるa, bって何?

→配列の中の要素のうちの1つがa、次の1つがbです。sort関数で数値を比較する際には引数abを必ず取ります。名前は別にabじゃなくてもいいです。

例えば配列numbersにある2をa、次の要素である5をbに入れてみます。

2と5を比較すると2 < 5となり、a < bの条件を満たすのでreturn -1の方を通ります。

また100をa、4をbとすると100 > 4となり、a > bの条件を満たすのでreturn 1の方を通ります。

このようにaには配列のうちの1つの要素、bには次の要素が入ることでその2つの数字の大小を比較しているわけです。この比較が順番を並べ替えるために使われます。

まずは「abは配列の中の要素なんだなー」ということを頭に入れておいてください。

 

if文のa < bとかa > bって何を比較しているの?

これは上で解説しましたね。

aには配列のうちの1つの要素、bには次の要素が入り、それぞれの数値を比較しています。

 

return -1とかreturn 1って何?

return -1return 1が何なのか知るために、まずはsort関数について知っておく必要があります。ここめっちゃ重要です。

sort関数は以下のルールに従って並び替えをしています。

  • コールバック関数が0未満(例えば-1)を返した場合:abの前に来る(順番は変わらない)
  • コールバック関数が0より大きい値(例えば1)を返した場合:baの前に来る(順番が変わる)
  • コールバック関数が0を返した場合:何もしない

例えばaに100, bに4が入っている場合、正しい順番に並び替えるにはbaの前に来させる必要があります。そして、そのためにはコールバック関数で0より大きい値を返せばいいということになります。

この「0より大きい値を返せばいい」という部分がelse if (a > b) { return 1; }です。

abを比較し、aの方が大きければreturn 1を返すことでsort関数がbaの前に持ってきてくれるというわけです。これにより4, 100という順番に並び替わります。

またaが2、bが5の場合はif (a < b) { return -1; }を通るので、「コールバック関数が0未満(例えば-1)を返した場合:abの前に来る(順番は変わらない)」にある通り、そのままの順番になります。

なお、aが2、bも2といった場合はelse { return 0; }を通るのでsort関数は何もしません。

これが繰り返されることによって数値の順番が並び替わっていくわけです。

 

なんだかごっちゃになりそうな人はとりあえず「正の数が返ったらソート」。これだけ頭に入れておけばokです。

 

つまり、最初に言った「return -1return 1って何?」に対する答えは、「sort関数が並び替え処理をするために必要な戻り値」ということになります。return -1return 1自体に特別な意味があるわけではなく、sort関数で並び替え処理するために必要なだけってことです。

ということは、別にreturnの値は1や-1じゃなくて3とか-100でも全然いいわけです。1や-1が返ること自体は重要ではありません。

まだイマイチよくわからない人はここを何回も読み直して具体的にイメージを膨らませてみてください。ここがsort関数で数値を並び替える上で一番重要です。

 

sort関数で降順で並び替える

さっきは昇順で並び替えをしましたが、降順で並び替えることもできます。

以下のサンプルは数値を降順で並び替えるコードです。

var numbers = [2, 5, 100, 4];

numbers.sort(function (a, b) {
  if (a > b) {
    return -1;
  } else if (a < b) {
    return 1;
  } else {
    return 0;
  }
});

console.log(numbers); // 結果:[100, 5, 4, 2]

前のコードと違う部分はif文の比較演算子が逆になっていることです。

例えばaが2、bが5の場合、else if (a < b) { return 1; }の処理を通ります。

sort関数はコールバック関数が0より大きい値を返した場合、baの前に来るので5, 2という順番に並び替わります。これを繰り返していくことで大きい数字がどんどん前に来て最終的に降順に並び替わります。

 

sort関数を簡潔に書く方法

上に書いたようなsort関数で並び替えをするコードはかなり簡潔に書くことができます。

以下のような書き方です。もしかしたらこっちのほうが見たことあるかもしれないですね。

var numbers = [2, 5, 100, 4];

numbers.sort(function (a, b) {
  return a - b;
});

console.log(numbers); // 結果:[2, 4, 5, 100]

このような書き方でも結果は全く同じになります。

やっていることは今までと同じで、引数aには配列のうちの1つの要素、bには次の要素が入ります。そしてsort関数は戻り値が0未満なら順番は変わらない、0より大きいなら順番を入れ替えるという処理をします。

仮にaが2、bが5の場合、2 – 5 = -3となり、戻り値は0未満なので順番は変わりません。

また、aが100、bが4の場合、100 – 4 = 96となり、戻り値は0より大きいので順番が入れ替わります。

これを繰り返すことで並び替えができます。配列の中に負の数が入っていても正しくソートできます。

 

return -1return 1自体に特別な意味があるわけではない」と前述した理由はこれです。要は正の数と負の数のどちらが返っているかがわかればいいので上のような書き方ができるわけです。

 

降順も簡潔に書く

上のような簡潔な書き方で降順にソートしたい場合は以下のように書けばokです。

var numbers = [2, 5, 100, 4];

numbers.sort(function (a, b) {
  return b - a;
});

console.log(numbers); // 結果:[100, 5, 4, 2]

上のコードと違うのはa - bb - aに変わっている点ですね。

これも今までと全く同じ考え方で理解できます。

仮にaが2、bが5の場合、5 – 2 = 3となり、戻り値は0より大きいので順番が入れ替わります。

また、aが100、bが4の場合、4 – 100 = -96となり、戻り値は0未満なので順番は変わりません。

これを繰り返すことで降順で並び替えができます。

 

どうでしょう?だんだん分かってきましたか?一度仕組みがわかってしまえば簡単です。

まだイマイチ理解できない人は本記事の最初の方を具体的な数値を当てはめて考えてみてくださいね。

jQueryでも並び替える

sort関数はjQueryでも使えます。

より実践的な使い方をするならHTMLの要素を並び替えたい場面とかですね。

以下のサンプルはボタンクリック時にHTMLのdata-index属性をもとにリストを並び替えるものです(右下のReturnでリロードできます)

See the Pen
by wagashi000327 (@wagashi000327)
on CodePen.

上はコードが若干見づらいのでjsのコードを載せておきます。

$(function() {
  $('button').click(function() {
    $('li').sort(function (a, b) {
      return $(a).data('index') - $(b).data('index');
    }).appendTo('ul');
  });
});

sort関数を使ってdata-index属性の順番通りに並び替わっているのが確認できます。

これも今までと考え方は同じで、$(a).data('index')が5、$(b).data('index')が2の場合、5 – 2 = 3となり、戻り値は0より大きいので順番が入れ替わります。

注意点として、sort関数終了後にそのままappendTo()をつなげてソートした要素を挿入しているのに気をつけましょう。

「sort関数が効かない」という場合はappendTo()しているか確認してみてくださいね。

 

sort関数は配列の数値じゃなくてもいい

上のサンプルを見て分かる通りsort関数で並び替えをする場合、比較するのは数値の大小だけじゃなくて要素のインデックス番号や文字列の長さなど正直何でもいいわけです。

というわけで色々ソートしてみましょう。

以下のコードは配列の要素を文字列の長さでソートするサンプルです。

var array = ['hoge', 'foo', 'fugafuga', 'bar'];

array.sort(function (a, b) {
  return a.length - b.length;
});

console.log(array); // 結果:["foo", "bar", "hoge", "fugafuga"]

文字数が少ない順に並び替えができていますね。

 

また、以下はオブジェクトのidをもとにソートするサンプルです。

var people = [
  { name: '山田', id: 8 },
  { name: '田中', id: 2 },
  { name: '佐藤', id: 1 },
  { name: '鈴木', id: 5 },
];

people.sort(function (a, b) {
  return a.id - b.id;
});

console.log(people);
/* 結果:
[
  {name: "佐藤", id: 1}
  {name: "田中", id: 2}
  {name: "鈴木", id: 5}
  {name: "山田", id: 8}
]
*/

こちらもオブジェクトのidの数値を使ってソートできました。

 

またこんなこともできてしまいます。

以下は配列classesの要素の順番通りにオブジェクトをソートするサンプルです。

var classes = ['部長', '課長', '係長', '社員'];

var members = [
  { name: '山田', clazz: '係長' },
  { name: '鈴木', clazz: '部長' },
  { name: '田中', clazz: '社員' },
  { name: '佐藤', clazz: '課長' },
];

members.sort(function (a, b) {
  return classes.indexOf(a.clazz) - classes.indexOf(b.clazz);
});

console.log(members);
/* 結果:
[
  {name: "鈴木", clazz: "部長"}
  {name: "佐藤", clazz: "課長"}
  {name: "山田", clazz: "係長"}
  {name: "田中", clazz: "社員"}
]
*/

配列にindexOf()をかけるとその要素の配列内でのインデックス番号を取得できます。'係長'なら2ですね(インデックス番号は0から始まるので)。

aが最初のオブジェクト、bが次のオブジェクトだとするとclasses.indexOf(a.clazz)はイコールclasses.indexOf('係長')なので2、classes.indexOf(b.clazz)はイコールclass.indexOf('部長')なので0となります。2 – 0 = 2で戻り値は0より大きいので順番が入れ替わります。

こんな感じであらかじめ「こういう順番でソートしたい」という配列を作っておけば、そのインデックス番号を使って配列やオブジェクトをソートしたりできます。

ちなみにclazzという名前にしている理由はclassは予約語だからです。

 

まとめ

sort関数はぱっと見どんな処理をしているのかよくわからないし、詳しく解説している記事がなかなか見つからなくて仕組みを理解するのに少し手間取りました。でも1度仕組みを理解してしまえば使うのは簡単です。

この記事でsort関数を理解する手助けになれば幸いです。

 

参考動画(英語)

YouTubeで探すと結構わかりやすい動画が出てきたりするのでググっても出てこなかったらツベってみるのがおすすめです。

スポンサーリンク
JavaScript
スポンサーリンク
でざなり