やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

JSで数値をソートすると文字列順になる罠

 [9,10,1].sort()の結果が[1,10,9]になってしまう。バカなの?

問題

 [9,10,1].sort()の結果が[1,10,9]になってしまう。もちろん期待値は[1,9,10]だ。

console.log([9,10,1].sort()) // [1,10,9]

お前はソートもできないのか? 使えねー

解決

 ソート順を決める関数を引数に渡す。

console.log([9,10,1].sort((a, b) => a - b)) // [1,9,10]

 引数を次のようにすることでソート方法を変更できる。

ソート (a,b)=>{}
昇順 (a, b) => a - b)
降順 (a, b) => b - a)

面倒くさっ こんなの覚えられないよ……

原因

 Array.sort()によると仕様である。

ソート順は昇順で、要素を文字列に変換してから、 UTF-16 コード単位の値の並びとして比較します。

 数値でソートして欲しかったのに、文字列に変換しやがる仕様のせいで今回のバグが起きた。

なんでや!

なぜこんな仕様になっているの?

 [9,10,1].sort()は見てのとおり数値の配列だ。直感的にみて、数値順でソートしてほしい。なのに、なぜ文字列順でソートする仕様になっているのか?

 原因は型がないせいだと思う。JavaScriptの言語仕様はタイプセーフじゃない。配列に入れる値の型は数値型であったり文字列型であったり、それらを混在させることができてしまう。たとえば[1,'A'].sort()など。それらをソートするなら、すべての型に共通するtoString()メソッドを使って文字列化してソートするしかない。だから文字列順ソートなのだと思う。

 C#など他の型があるタイプセーフなプログラミング言語なら、List<int>のようにジェネリクスで配列要素の型を限定できる。これによりソートアルゴリズムもその型にあわせたものになってくれる。数値型なら数値順でソートする。私はそれを期待していた。でもJavaScriptはタイプセーフ言語じゃないから文字列ソートになってしまう。

 こんなひどい罠があるとは……。

やっぱJavaScriptってクソだわ

情報源