JSのsort()で数字のソートができない問題
jsで [1, 30, 4, 21, 100000] という数字を配列をソートしたい時、sort()を使うと、[1, 4, 21, 30, 100000] とならずに、[1, 100000, 21, 30, 4]という風になってしまいます。
https://gyazo.com/5400813b9946be1a7d71cc1d8fe2ca64
これはsort() をする際に全ての配列要素が文字列に変換された後にソートされてしまうためです。
compareFunction (比較関数) が与えられなかった場合、undefined 以外のすべての配列要素は文字列に変換され、文字列が UTF-16 コード単位順でソートされます。例えば、"banana" は "cherry" の前に来ます。数値のソートでは、9 が 80 の前に来ますが、数値は文字列に変換されるため、Unicode 順で "80" が "9" の前に来ます。undefined の要素はすべて、配列の末尾に並べられます。
その対策となるのが、比較関数です。
code:js
arr.sort(compareFunction);
実はsort()は上記の様に引数として、何をもって並び替えるのかを定義する関数を与えることができます。
その関数が比較関数になります。MDNから説明を引用したものを下に記載しています。
compareFunction が与えられた場合、undefined 以外のすべての配列要素は比較関数の返値に基づきソートされます (undefined の要素はすべて、compareFunction を呼び出すことなく配列の末尾へ並べられます)。もし a と b を比較しようとする場合は、次のようになります。
・compareFunction(a, b) が 0 未満の場合、a を b より小さいインデックスにソートします。(つまり、a が先に来るようにします)
・compareFunction(a, b) が 0 を返した場合、a と b は互いに変更せず、他のすべての要素に対してソートします。注意: ECMAScript 標準はこの振る舞いを保証していないため、一部のブラウザー (例えば、遅くとも 2003 年以前のバージョンの Mozilla) はこれを遵守していません。
・compareFunction(a, b) が 0 より大きい場合、b を a より小さいインデックスにソートします。(つまり、b が先に来るようにします)
・compareFunction(a, b) に与えられた引数が同じなら返値も同じでなければなりません。もし一貫性のない値を返した場合の挙動は未定義となります。
つまり、aとbの差を取る関数を書くことで数字のソートができる様になります。
昇順ソート
code:js
numbers.sort((a, b) => a - b);
降順ソート
code:js
numbers.sort((a, b) => b - a);