JavaScriptの動かないコード(中級編) 配列のsort結果がおかしい …評価関数が正数か負数以外の値を返す場合の挙動のエラー
以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)
やりたい事:
- オブジェクトの配列を,年齢の若い順に並び替える。
// WSHの場合はalertを定義しておく if( typeof alert == "undefined" ){ var alert = function(s){ WScript.Echo(s); } } // 「名前」と「年齢」を持った // オブジェクトの配列 var arr = [ { name : "太郎", age : 21 }, { name : "花子", age : 9 }, { name : "次郎", age : 19 }, { name : "マルガリータ", age : 49 } ]; // 年齢の若い順に昇順ソート arr.sort(function(o1, o2){ // 年齢を比較 return o1.age > o2.age; }); // ソート結果を表示 for( var i = 0; i < arr.length; i ++ ){ alert( arr[i].name ); }
結果として「花子,次郎,太郎,マルガリータ」の順番で表示されれば成功。
発生する不具合
まったくソートされない。
「太郎,花子,次郎,マルガリータ」と表示され,並び替え処理が実行されていないことが分かる。
理由
sort() の引数として渡す評価関数は,ブール値 (true / false) を返す仕様ではない。
「正の数」「負の数」「0」のいずれかを返さなければならないのだ。
それ以外の値を返すと,思ったようなソート結果にはならない。
さらに言えば,「0」を返却した場合も挙動が不安定になり
ブラウザ間での出力結果が変わってしまう。
javascript - Chromeでの文字列配列ソートがおかしい - スタック・オーバーフロー
http://ja.stackoverflow.com/questions...
- なぜかブール値を返すものと勘違いしていました。
- オブジェクトのソートを行なう場合で、各種ブラウザ間でソート結果を同じにしたい場合は、0を返さないようにする必要があります。
- 比較関数が return 0 した場合、ブラウザによっては並び替えたり、並び替えなかったりする
JavaScript の Array#sort で return 0 すると要素の順番は不定になります - latest log
http://uupaa.hatenablog.com/entry/201...
- 評価関数の中で return 0 してしまうと要素の順番は保証されません。 return 0 を使わずに記述してください。
その他,JavaScriptの sort 関数でつまずきがちなポイント:
JavaScriptでうっかりやってしまいそうなこと色々 : アシアルブログ
http://blog.asial.co.jp/1092
- Array#sortのデフォルトのソート順は「文字列比較による辞書順」と定義されている。
- 「1, 2, 3, 10, 100」とならず,結果は「1, 10, 100, 2, 3」
JavaScriptのsortは必ずしも安定ではないのを覚えといてね - by edvakf in hatena
http://d.hatena.ne.jp/edvakf/20090607...
- JavaScriptのソートは必ずしも安定的ではない
- つまり、等価と比較された要素が, 元の順で残るとは限らない
解決策
うっかりboolを返したくなるので,気をつけて実装しなおそう。
評価関数の中で +1 または -1 を返すように改変する。
// 年齢を比較 return o1.age > o2.age; ↓ return ( o1.age > o2.age ) ? 1 : -1;
これで,冒頭のコードは意図通り
「花子,次郎,太郎,マルガリータ」の順番にソートされる。
関数の仕様をよく確認しよう。
関連する記事:
JavaScriptの動かないコード (初級編) 関数に配列を渡すときのエラー
http://language-and-engineering.hatenablog.jp/entry/20080921/1221926545
JavaScriptの動かないコード (中級編) 動的追加したイベントの実行順序 ( addEventListener vs attachEvent )
http://language-and-engineering.hatenablog.jp/entry/20081011/1223680300
JavaScriptの動かないコード (中級編) jsonオブジェクトをevalできないエラー
http://language-and-engineering.hatenablog.jp/entry/20081022/1224597688
JavaScriptの動かないコード (中級編) かけ算を間違える
http://language-and-engineering.hatenablog.jp/entry/20080913/1221303278