アプリ版:「スタンプのみでお礼する」機能のリリースについて

入門本に、次のような例題がありました(主要部分の抜粋です)。

@list = (20,25,24,32,28,20,28,24,20); #年齢リスト
foreach $fld(@list){
  $syukei{$fld}++;
}
print "<table><tr><th>年齢</th><th>人数</th></tr>\n";
foreach $key( reverse( sort( keys( %syukei ) ) ) ){
  $cnt = $syukei{$key};
  print"<tr><th>${key}才</th><th>${cnt}人</th></tr></table>\n";

これの実行結果は、@list の年齢を各年齢ごとにカウントして、表に各年齢が何人であるかを表示します。

・$syukei{$fld}++; の部分は $ハッシュ名{'キー名'} でハッシュを作ろうとしているのだと思うのですが、++ がなぜ付くのか分かりません。
・↑の考え方が合っているとしたら、$cnt = $syukei{$key} で右辺は $ハッシュ名{'キー名'} を表しているのだと思うのですが、左辺がスカラー値を求めている場合はキーの数を返すというルールがあるのでしょうか?

私の質問にこだわらず、分かりやすく全体の説明をして頂ければ助かります。

A 回答 (3件)

手ごわいですね。

敢えて説明に挑戦してみます。

どうも、ハッシュの概念またはハッシュの記法の
理解が間違っておられるように見受けられますが。

ハッシュって要はExcel(じゃなくてもいいですが)の
表みたいなもんで、表の左端の列に書かれてる内容で
行を特定する、というイメージです。

回答者   回答日
deagle   01-09-07
zeyper   01-09-07
Fooky   01-09-09

という表があったとします。表の名前はAnsDateとでも
しましょうか。ハッシュでは、回答日を取り出すのに、
回答者の名前を使って取り出せる、ということです。
ですから、print $AnsDate{'Fooky'}; の実行結果は
01-09-09となります。このときの回答者名が
「ハッシュキー」、回答日が「ハッシュ値」となります。
表全体が「ハッシュテーブル」、各行が「ハッシュ」と
呼ばれます。

1つ、Excelの表と違うところは、同じ回答者名を持った
行(=同じハッシュキーを持つ異なるハッシュ値)はつくれない、
ということです。ですから、ここで新たに全く同じハンドル
ネームのFookyって人が、10日に回答をしてしまうと、
$AnsDate{'Fooky'} = '01-09-10';という代入が為され、
先程の表は

回答者   回答日
deagle   01-09-07
zeyper   01-09-07
Fooky   01-09-10

となってしまいます。

一方、普通の配列は、何行目かを指定することで
データを取り出す表、というイメージになります。
ですから、先程の表は、

番号  回答日
0   01-09-07
1   01-09-07
2   01-09-09

となり、0番目の回答者が何日だったかなぁってことで、
print $AnsDate[0];として、01-09-07を取り出します。

ちょっと難しく考えすぎではないですか?
要素番号でしか参照できない配列が、
もうちょっと使いやすくなって、要素番号の
ところに任意の文字列が使えるようになった
だけのことなんですが。

さて、例題のforeachのところを展開してみると、

$syukei{'20'}++;
$syukei{'25'}++;
$syukei{'24'}++;
....
$syukei{'28'}++;
$syukei{'24'}++;
$syukei{'20'}++;

という処理が順に行われているだけです。

ここで新たに問題になるのは、$syukei{'20'}という
のは初めて出て来たので、文字列'20'をキーとする
ハッシュはまだ存在しない(=まだ表の左端に20
と書かれた行が存在しない)ということです。

まだ存在しないハッシュ値に対して、1増やす、
という算術演算を施したらどうなるのか?

答えは、'20'をキーとして、ハッシュ値が'0'である
ハッシュが自動的に作成され、それに1増やす
という処理が行われます。

そうすると、最終的に、

$syukei{'20'} == 3, $syukei{'25'} == 1, $syukei{'24'} == 2,
$syukei{'32'} == 1, $syukei{'28'} == 2

という結果になるのは、不思議ではないと思うんですが。

しつこいようですが、この結果を表として書くと、

年齢   人数
20    3
25    1
24    2
32    1
28    2

という表になります。

例題の後半は、年齢の大きいものから順に表示される
ように工夫しているだけです。
    • good
    • 0
この回答へのお礼

ありがとうございます!ゆっくり考えて、大方理解できました。
私が分かってなかったのは、$syukei{$fld}++; の加算がどの時点行われるか、ということです。私は $fld の値(年齢の数値)に加算されるものだと勘違いしていました。
Fookyさんのおっしゃる「存在しない値に1を加算する」という概念がなかったんです。

foreach $fld(@list){
  $syukei{$fld}++;
の時点で、目には見えないけどハッシュテーブルを作ってるんだと理解すれば、$syukei{$fld}++; の指し示す行へ1が加算されるのも分かります。

その後の
foreach $key( reverse( sort( keys( %syukei ) ) ) ){
  $cnt = $syukei{$key};
も、それで理解できました。

お礼日時:2001/09/10 10:28

初めまして、私も最近勉強を始めたものです。



まず、ハッシュとは
aaa-bbb0-ccc0
  -bbb1-ccc1
  -bbb2-ccc2
と言う感じになっていてこれは、%aaaというハッシュになります。
%aaaのbbb0の中に、ccc0と言う値が入っているわけです。
ちなみにこれが@aaaだと、bbb0は数字0、bbb1は数字1でccc0がその値となります。
ですから、ハッシュとは、値(ccc)を入れるだけでなく、その値の入っているキー(bbb)も決められる、配列(@)のパワーアップ版みたいなものだと思ってください。
余計に分からなくなったらすいません。

ハッシュが分かったところで(分からなくても(笑))上のプログラムは、
syukei-20-3
   -24-2
   -25-1
   -28-2
-32-1
と言うハッシュになります。++は下の専門家の言った通りだと(下を読んで初めて知った)数字を1足す、"$***++"と同じ効果があると言うことなので、
syukei-20-
と初めて20を出したら++で
syukei-20-1
とし、もう一度20を出したら++で、
syukei-20-2
として、それを最後に
$cnt = $syukei{$key};
で$cntに値を入れているというわけです。ちなみにこの時$keyが20だと
3 = $syukei{20};
となります。

こんな雑な説明でわかっていただけたら幸いです。
最後にこの時
$abc = @list;
とやると$abcには9が入ります。
配列をスカラー変数に入れると、配列の中のリストの数を返します。
$ハッシュ名{'キー名'} はキー名の中のスカラー変数を表しているので、$***の中にはスカラー変数を返しているだけです。
    • good
    • 0
この回答へのお礼

ありがとうございます。しかし、
foreach $fld(@list){
  $syukei{$fld}++;
}
の部分は $fld に @list の要素を一通り代入しなさい、という命令ですよね?
それがなぜ @list の各要素をキーとして代入し、その登場回数を値として代入するのかが分かりません。
配列をスカラー変数に入れると、配列の中のリストの数を返すというのは分かりましたが、 「$ハッシュ名{'キー名'} はキー名の中のスカラー変数を表しているので、$***の中にはスカラー変数を返しているだけです。 」という説明が分かりません。

お礼日時:2001/09/07 20:58

 またまた登場(笑)


 えー。まずこのプログラムは、ハッシュ配列 syoukei に、年齢をキーとしてその人数を入れ、逆順ソートした上で出力する、というものですね。
 ちょっとばかしHTMLの組み方がおかしいようですが(笑)

 で、ご質問の部分、の「++」は、これは単純に「カウントアップ」の意味です。
 $syoukei{$fld} には「$fld 歳」の人の人数が入っているわけですから、これにプラス1しているのです。これを、インクリメント機能と呼びます。
 このカウントアップ自体はハッシュに関する機能ではなく、すべての変数に対して使うことが出来ます。

 (すべての変数は未定義状態では0、null、undefine のいずれかであると定義されるので、最初のカウントアップの直後には変数の値は1になります)
 逆に $syoukei{$fld}--; とするとこれはカウントダウンで、マイナス1されます。

 ですので、$cnt = $syoukei{$fld} では、$cnt に単純に、カウントアップして得られた集計結果を代入しているだけということになります。
    • good
    • 0
この回答へのお礼

@list = (20,25,24,32,28,20,28,24,20); #年齢リスト
foreach $fld(@list){
  $syukei{$fld}++;
}
print "<table><tr><th>年齢</th><th>人数</th></tr>\n";
foreach $key( reverse( sort( keys( %syukei ) ) ) ){
  $cnt = $syukei{$key};
  print"<tr><th>${key}才</th><th>${cnt}人</th></tr></table>\n";

私の解釈では、
■foreach $fld(@list){ は、@listの要素を一通り$fldにする→従って $syukei{$fld} は $syukei{$20} など@listにある年齢を入れたもの9つを用意する→$syukei{$20}++ なんていう文は成り立たないのでは?

となって、止まってしまいます。

お礼日時:2001/09/07 21:17

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!