スポンサーリンク

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