【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」と、第一引数と第二引数の順序を入れ替えればいい。