NACの勉強の経過を綴るところ

個人的なコードの勉強

【JS】配列の並べ替え

JS逆引きレシピ本、095(P154)。


最近の仕事で、配列のソートで結構悩んだので、改めて整理しておきたい。


ソートの構文は以下。

arr.sort( function(e1, e2) {
    // 処理
});

この「e1, e2」っていうのが、ソートの際に比較する要素らしいのだが、これが分かりづらい。


例えば、数値として「7, 38, 21」という配列があった場合、何も引数として持たずにsortメソッドを使うと、辞書的なソートをしてしまう。

let data = [7, 38, 21];
concole.log(data.sort()); // [21, 38, 7]

これを避けるためには、以下のような書き方をする必要がある、わけだが……

let data = [7, 38, 21];
let numArray = data.sort( function(m, n) {
    return m - n;
});
console.log(numArray); // [7, 21, 38]

……すっげぇ、分かりづらくない?


上記の構文で、「m」「n」が何を意味するのか、わかるだろうか。
「return m - n;」も、なにをやってるのかパッと見、よくわからないし


ただ数値でソートしたいだけなのに、なんでイチイチこんなことをしなくちゃいけないのか。
JavaScriptが、ただただ面倒な言語だな、という気にさせられてしまう。

sortメソッドの処理

整理するためには、まずsortメソッドにはどんな値を渡す必要があるのか、
そこから考えるのが、分かりやすい。


sortメソッドには、引数として比較関数を指定する、……もう、そういうもの、と、ここは飲み込む。


比較関数とは、以下のような関数を言う。

function compare(a, b) {
  if (ある順序の基準において a が b より小) {
     return -1;
  }
  if (その順序の基準において a が b より大) {
     return 1;
  }
  // a は b と等しいはず
  return 0;
}

要するに、比較関数とは、その戻り値が「正 , 0 , 負」のいずれかであり、それ以外はありえない。
sortメソッドは、その戻り値によって処理をするもの、ということである。


今回の

let data = [7, 38, 21];
let numArray = data.sort( function(m, n) {
    return m - n;
});

の例で行くと、「m」「n」は、配列の中の2つの値が代入される。
関数の中で、その2つの値を比較。
sortメソッドはその結果を受け取ってソートを行う。

値の関係 計算 返り値 結果
m > n m - n = 正の値 mのほうが後に来るようにソート
m == n m - n = 0 0 順番はわからない
m < n m - n = 負の値 mのほうが前に来るようにソート

つまり、
1)7と38を比較。7のほうが小さいので、7が前に来る。
2)38と21を比較。21のほうが小さいので、21が前に来る。
3)7と21を比較。7のほうが小さいので、7が前に来る。
→結果、「7,21,38」という順番になる。


……ということを、全パターンで比較しているということ?
本当に?


いかにも処理が重そうだけど、冷静に考えたら、たとえ一発でソートしてくれる命令があったとしても、言語内部では同じアルゴリズムで処理をしていることになるから、重さとしては変わらないのかなぁ。その処理の内容が表に出ているか、裏で行われているかの違いだけで。
煮え切らない思いもあるけれど、そういうものと思うしかなさそうだ。
なんとなく、構文の中身が直感的じゃないので、毎回書こうとするときに悩んでしまうんだよなぁ。


ちなみに上記の例は昇順の場合で、降順の場合は「return n - m」と、第一引数と第二引数の順序を入れ替えればいい。