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

@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} で右辺は $ハッシュ名{'キー名'} を表しているのだと思うのですが、左辺がスカラー値を求めている場合はキーの数を返すというルールがあるのでしょうか?

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

このQ&Aに関連する最新のQ&A

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に関連する人気のQ&A

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qif($key){ ($key eq 'aaa') || ~~を複数縦に記述したい

sub AAA {my($key)=@_;
if($key){
($key eq "aaa") || ($key eq "bbb") || ($key eq "ccc") || ($key eq "ddd") || &Error("$keyが不正です。");
}
}

のような形があるとして、$key eq "" の数が50個近くあるような場合、横に表示するのではなく縦に
($key eq "aaa") ||
($key eq "bbb") ||
($key eq "ccc") ||
($key eq "ddd") ||
と、見栄えよく表示させたいのですが
どのように記述すればよいのでしょうか。

また代替案などありましたらあわせてご教授頂けますと幸いです。

Aベストアンサー

正規表現で

$key =~ /^(
aaa|
bbb|
ccc|
ddd)$/x || &Error("$keyが不正です。");

Q$hts =~ s/##([^#]+)##/$FORM{$1}/g の意味を教えてください!

お世話になります。
perl素人なのですが必要に迫られてWEBで調べながら
ソースを解析していますが、次のコードで完全に止まってしまいました。

$hts =~ s/##([^#]+)##/$FORM{$1}/g

この場合、
#hts から ##([^#]+)## を探して $FORM{$1} に全て置き換えようとしていると思うのですが、以下2点が理解できず困っています。

1.##([^#]+)## の意味
$htsに##で囲まれた文字列が複数あるのでそれら全てを探すということでしょうか?

2.$FORM{$1} の意味
$1は1.で検索した結果だと思いますが、$FORM{ }は一体なんでしょうか?

素人がいきなり解析するのは無謀なのは承知の上ですが、
どうしても業務で必要なので、お知恵をお貸し下さい。
よろしくお願いいたします。

Aベストアンサー

1.
perlを基準に「正規表現」で調べてごらん

2.
同じくperlでHTMLのformデータを受け取る方法を調べてごらん

Q$in{'~'}を$~に変換

CGIを改造中です。
変数の処理なのですが、サブルーチン内で利用するときに「$in{'~'}」と言う形でしか表示してくれません。これを「$~」の形にしたいです。
数が少なければ「$~ = $in{'~'}」を個数書けばいいのでしょうけど、結構数があるので、何か簡単な方法で変換できないかと考えています。
良い方法があれば教えてください。

Aベストアンサー

ハッシュのままで何か不都合があるのかなと
疑問に思いつつ・・・
#実際ハッシュは
#「(変数の)値に別の値を対応させる」
#ために存在するわけだから

けど,まあ,やろうと思えばkeys関数でできますよ.

%in=(
'X' => 1,
'Y' => 2,
'Z' => 3,
);

for $key (keys %in){
${$key}=$in{"$key"};
print "key; $key ${$key}\n";
}

print "$X $Y $Z";

strictとwarningsのプラグマを外さないといけないので
副作用の方が大きいでしょうが.

Q変数 $abc と ${abc}

$abcを
${abc}と書くのはなぜですか
よろしくお願いします。

Aベストアンサー

正確なところは知らないのですが、
{}で囲むと変数名を明確にすることができます。
$abc = "123";
の時、$abc . "456"のつもりで
print "$abc456";
とすると、変数abc456の内容が出力されます。
一方、print "${abc}456";
とすると、上手く行きます。

Qwhile(<ハンドラ>) {} で行数をカウント

こんにちは。

掲示板をperlで作るという課題に取り組んでいるのですが、下記の部分の
動きだけがどうしても期待する動作がえられず、困っています。
なにか試した方が良い事がありましたら、ご指摘いただけないでしょうか。

プログラムの説明:
POST されたコメントを data.dat に追記していくプログラムです。
ファイルハンドラから一行づつ読み込んで、行数を $count でカウントし、
『X行目&&コメント』のようにコメントの先頭に行数を表示します。


#!/usr/bin/perl
$myfile = 'data.dat';

(省略)

sub piyo{
open(HOGE, ">> $myfile");
flock(HOGE, 2);
my $count = 1;
while(<HOGE>){
$count++;
};
print HOGE "$count行目&&in{'comment'}\n";
close(HOGE);

};


data.dat の期待する結果は下記です。

1行目&&コメント
2行目&&コメント
3行目&&コメント
.....

実際に data.dat に書き込まれた結果は下記でした。

1行目&&コメント
1行目&&コメント
1行目&&コメント
.....


試した事1:
open(HOGE, ">> $myfile");

open(HOGE, "+>> $myfile");
した。

試した事2:
while(<HOGE>){
$count = $count + 1;
};
とした。


どちらでも結果に違いがありませんでした。


よろしくお願いします。

こんにちは。

掲示板をperlで作るという課題に取り組んでいるのですが、下記の部分の
動きだけがどうしても期待する動作がえられず、困っています。
なにか試した方が良い事がありましたら、ご指摘いただけないでしょうか。

プログラムの説明:
POST されたコメントを data.dat に追記していくプログラムです。
ファイルハンドラから一行づつ読み込んで、行数を $count でカウントし、
『X行目&&コメント』のようにコメントの先頭に行数を表示します。


#!/usr/bin/perl
$myfile = 'data.dat';

(省略)

sub pi...続きを読む

Aベストアンサー

+>>をご使用なので、ファイルハンドラが最後に移動してないでしょうか。
ハンドラが最後に移動しているので、whileは実行されておらず、常にファイル末尾に1行目が出力されるというシナリオを想像します。

Perlfaqを使用して…

$lines = 0;
$filename = "yahho.txt";
open(FILE, "+<$filename") or die "Can't open `$filename': $!"; #open に+<を使用
while (sysread FILE, $buffer, 4096) {
$lines += ($buffer =~ tr/\n//);
print "p";
}
print FILE ++$lines . "やっほ~\n";

注意 open時にファイルの存在は保証してください。存在しない場合エラーです。


おすすめ情報