みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

Arrayオブジェクトのsort()メソッド

テキストに書いているArrayオブジェクのsort()メソッドを実行しました。
ソースコードは以下のとおりです。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-type" content="text/html; charset=UTF-8">
<title>Arrayオブジェクトのメソッド</title>
<script type="text/javascript">
</script>
</head>

<body bgcolor="#FFFFFF">
<p style="font-size:200%">
<script type="text/javascript">
var ages = new Array(4, 6, 10, 24, 1, 11, 40);
ages = ages.sort();
document.write(ages.join(" > "));
</script>
</p>
</body>
</html>

すると、ブラウザにこのように表示されました。
(ちなみに > は矢印記号で大小を比べるものではありません。)

1 > 10 > 11 > 24 > 4 > 40 > 6

これを見る限り数字の順番が変わっています。
テキストでは、これを「文字列として昇順に並び替えた」と書かれているのですが、私の知識の足りなさから意味がよく分かりません。
ただ、昇順の意味は分かっているつもりです。
もし、昇順に並び替えるのなら、

1 > 4 > 6 > 10 > 11 > 24 > 40

のようになるのではないでしょうか。

頭の悪い私のために是非ともアドバイスを頂ければ大変助かるのですが。
どうぞ宜しくお願い致します。

投稿日時 - 2011-05-06 18:15:52

QNo.6718403

困ってます

質問者が選んだベストアンサー

> 2桁も3桁も頭の部分が比較されるので良いのでしょうか。

はい処理体系によって違いますがJavaScriptの標準ソート関数では1文字毎に比較されます。
比較する文字列を並べて頭から1文字づつ比較して行き大小判定が決まった所で確定します。

(1) 最初に1文字目を比べて見て大小を決めます。
(2) もし1文字目が同じなら、2文字目を見比べて大小を決めます。
(3) もし片方に2文字目が無ければ、ない方を小さいと決めます。
(4) もし双方同じコードなら3文字目以降を(b)からと同様にループ。
(5) 最後まで判定が付かなければ同じ文字列だとします。

と言う感じですが、解りますか?
他言語なら文字列ソートって文字列比較関数を使って回してるので比較的解り易いんですが…
普通にありそうな関数がJavaScriptに無いので理解が遠回りになるのかもしれません。

投稿日時 - 2011-05-06 22:22:13

お礼

再度の回答に感謝します。
お手数をおかけして申し訳ありませんでしたが、これで99%は理解できたと思っています。
本当にありがとうございました。

投稿日時 - 2011-05-07 01:48:00

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(8)

ANo.8

#3-4 です。

今回、prototype は本題ではないので覚えなくて大丈夫です。
Array.prototype.sort が [].sort() と同じものという認識さえあればOK.
リファレンスとしては MDC がわかりやすいかもしれません。MDC は Firefox を開発している Mozilla が運営しており、信頼性の高いサイトです。

sort - MDC Docs
https://developer.mozilla.org/ja/Core_JavaScript_1.5_Reference/Global_Objects/Array/sort

"文字列の代わりに数字を比較する場合、比較関数は単純に a から b を引けばよいでしょう。" というわけで、下記で十分でしたね。

function compareNumbers (a, b) {
 return a - b;
}
var a = [4, 6, 10, 24, 1, 11, 40].sort(compareNumbers);
alert(a); // [1, 4, 6, 10, 11, 24, 40]

比較関数 (compareNumbers) のルールは MDC に記載があるので参考にしてみてください。

投稿日時 - 2011-05-07 17:44:08

お礼

今回は再度の回答を頂き、感謝の念に絶えません。
まだまだ初心者の私にはprototypeは少し早すぎるのかもしれません。
それでも、回答者さまの書かれたcompareNumbers()関数はテキストの後ろの方に書かれていたものと完全一致しました。
これで、回答者様のアドバイスは99%理解できたと思います。
本当にありがとうございました。

投稿日時 - 2011-05-07 22:10:30

ANo.7

return (a>b)-(a<b);

なにげに、かんどうしたこーど。

投稿日時 - 2011-05-07 12:48:40

ANo.6

#2です。
疑問はつきないですね。
半分釣りかとも思ったのですが、素直に学習意欲ということで受け止めます。

さて、場合にもよりますがひとつの質問のなかであまり連鎖的に質問すると
却ってわかりづらくなりますので、一度ご自身で調べた上で
わからない点は別途質問を立てたほうがよいかもしれません。

今回のものは単純なのでとりあえずざっと・・・

>理解は難しかったのはmysort()関数についてです。

やっていること自体はおそらく質問者さんのおもっているとおりで、
具体的には#3さんが解説しているとおりです。
sortにユーザー関数を指定すると、配列の二つの値を比較して
その戻り値である-1か0か1のいずれかを見て、ルールに従いソートする
という感じです。
なぜそうなるのかなどは面倒な話になるので割愛します。

>return a==b?0;(a>b?1-1);
ただしくは、return a==b?0:(a>b?1:-1);

これは三項演算子といって、?と:の組み合わせで処理を行います。
「条件?正の値:偽の値; 」という書式です。今回は
条件1?正の値:(偽の値がさらにわかれ条件2?正の値:偽の値);
といった組みあわせで使ったのでやや見にくかったかも知れません。
使い方次第ですが単純比較の場合、ifより見やすく(簡潔に)書くことが
できる場合もあります。
もっぱらこの書式を使うかどうかは好き嫌いによります。

投稿日時 - 2011-05-07 12:39:15

お礼

再度の回答を頂き、感謝します。
厳しいアドバイスもありましたが、それは全ての回答者様の意見を見ての事でしょうか。
確かに、回答者様のおっしゃられている事も分かります。
ただ、釣りというのはよく分かりません。
三項演算子に関しては理解できたと思います。
本当にありがとうございました。

投稿日時 - 2011-05-07 22:20:29

ANo.4

#3 です。

コメントは [1, 4, 6, 10, 11, 24, 40] の間違いでした。
あと、yambejp さんと内容が重複してしまいました。すみません。

投稿日時 - 2011-05-06 19:16:00

ANo.3

Array.prototype.sort() は引数がないとき、各要素値を String 型に変換して文字列比較でソートするからです。
例えば、"10" と "4" を比較する場合、一文字目の "1" と "4" を比較してソートしているので、"10" が前になります。
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/15-4_Array_Objects.html#section-15.4.4.11

数値比較するには引数を指定してください。

var a = [4, 6, 10, 24, 1, 11, 40].sort(function (a, b) {
 if (a > b) {
  return 1;
 }

 if (a < b) {
  return -1;
 }

 return 0;
});
alert(a); // [1, 10, 11, 24, 4, 40, 6]

投稿日時 - 2011-05-06 19:13:30

お礼

回答を頂き、感謝します。
まだprototypeというものを勉強していないので、これが有るのと無いのとではどう違うかは分からないのが残念で仕方ありません。
それによって、わざわざ貼り付けて頂いたURLのサイトに関しても今一理解できませんでした。
もちろん、全然分からなかった訳ではありません。
後、書いて頂いたソースコードについては理解できたつもりでいます。
本当にどうもありがとうございました。

投稿日時 - 2011-05-07 02:18:48

ANo.2

普通にsortをするかぎり、でてきた文字の先頭から評価されます。
自然順にソートする場合は若干工夫が必要です。

<script>
function mysort(a,b){return a==b?0:(a>b?1:-1);}
var ages = new Array(4, 6, 10, 24, 1, 231, 157 ,16, 40);
ages = ages.sort(mysort);
document.write(ages.join(" > ")+"<br>");
//数値の比較だと自然順

var ages = new Array("4", "6", "10", "24", "1" ,"231" , "157", "16", "40");
ages = ages.sort(mysort);
document.write(ages.join(" > ")+"<br>");
//文字列の比較だと先頭から評価

</script>

もうすこし慣れてくると無名関数などで処理することもできますが、
それは追い追い学習してください。

投稿日時 - 2011-05-06 19:09:06

補足

理解は難しかったのはmysort()関数についてです。
これは引数aと引数bに関して、引数aの値と引数bの値がイコールなら0を返し、
引数aの方が引数bよりも大きかった場合1-1で合っているのでしょうか。
もう1つの疑問はreturnのところの記述の仕方に関してです。

return a==b?0;(a>b?1-1);

この部分が今一理解できません。
お手数をおかけして大変申し訳ないとは思いますが、ここの部分に関する説明を書いて頂けないでしょうか。
再度のアドバイスどうぞ宜しくお願い致します。

投稿日時 - 2011-05-07 02:06:12

お礼

噛み砕いたアドバイスを頂き、感謝します。
ただ、初心者の私には多少難しい部分があります。
その点に関しては補足に書かせて頂きます。
もちろん、回答者様は何も悪い部分は無く、私の理解が追いつけない事を付け足しておきます。
アドバイスどうもありがとうございました。

投稿日時 - 2011-05-07 01:55:36

ANo.1

見た目は同じなのですが、数値と文字列ではプログラムでの内部格納方法が違います。

数字1は内部「0x00000001」と格納、文字列"1"は「0x31」と格納。
数字4は内部「0x00000004」と格納、文字列"4"は「0x34」と格納。
数字6は内部「0x00000006」と格納、文字列"6"は「0x36」と格納。
数字10は内部「0x0000000A」と格納、文字列"10"は「0x31,0x30」と格納。
数字11は内部「0x0000000B」と格納、文字列"11"は「0x31,0x31」と格納。

格納方法も違うのでソート方法も違って、数値は1つとしてソートされますが、文字列は頭から1つづつソートされます。
文字列での内部格納状態を見て下さい、頭が 0x31 となっている方が 0x34や0x36より小さいので前に並ぶ事になります。
JavaScriptなどでは数値と文字がかなり近しい関係で扱われるので誤認されやすいですが実際内部の扱いが違うんです。

こんな説明で解りますか?

投稿日時 - 2011-05-06 18:31:03

補足

お礼の部分にも書いたのですが、ある部分だけ理解に苦しむ点があります。
1桁の大小の違いは回答者様の説明で分かりましたが、2桁の数字の場合ですね。
いや、再度読んだ結果ですが、2桁も3桁も頭の部分が比較されるので良いのでしょうか。
大変すいませんが、再確認と言う事で書かせて頂きました。
この理解の仕方で正しいのでしょうか。
再度のアドバイス宜しくお願い致します。

投稿日時 - 2011-05-06 18:58:31

お礼

噛み砕いた分かりやすい回答を頂き、感謝します。
回答者様の説明は大分理解できました。
ただ1つだけですが、確認したいと思う部分があるので、それは補足とさせて頂きます。
恐れ入りますが、再度アドバイスを頂ける事と大変助かります。

投稿日時 - 2011-05-06 18:51:02

あなたにオススメの質問