- ベストアンサー
perl キーの集計について foreach文
@list=(20,25,24,32,28,20,28,24,20); という、ある組織の人間の年齢の配列を定義したとします。 そこで、 foreach $fld(@list){ $syukei{$fld}++; } というforeach文によって、年齢を「キー」として集計していくという説明を受けたのですが、いきなりスカラー変数の$syukeiが出てきて、さっぱりわかりません。 $syukei{$fld}++; という一行の意味を教えてくださらないでしょうか。 また、++という記号を使用していますが、これを別の書き方で書き換えることはできないでしょうか。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
> その場合なんですが、%syukeiの使用宣言というのは、 > 何をすればいいのでしょうか。 とりあえず、↓かな。 %syukei = (); これは「宣言」というほどのものではありません。 単なる「初期化」です。 しかも Perl が自動的にやってくれていることを、改めて書いています。 一見ムダのようですが、人が「プログラムを読む」ときに、これは宣言と同等の意味を持ちます。 たとえば、後にコードをメンテナンスしたり、他の人と共有することになったときに、これがないと1からコードを解読するハメになったりします(苦笑)。 さらに用途をコメントしておくなどすると、よりよいでしょう。 # 人数カウント用ハッシュ(キー:年齢、値:人数) %syukei = (); また、より高度な話になってしまいますが、こんな宣言方法もあります。 my %syukei; これは「変数のローカライズ」というもので、変数を限定された場所だけで利用する場合の「宣言」です。(上記の単なる初期化とは異なります。) これを理解するには、まず「変数のスコープ」についての理解が必要なので、後の課題とされるとよいかと思います。 大きなスクリプトを書く時には必要にもなってきますが、今は特に気にしなくてもよいでしょう。
その他の回答 (4)
- leaz024
- ベストアンサー率75% (398/526)
「ハッシュ(連想配列)」というのはご存知ですか? これは配列と同様に、1つの変数内にいくつもの値を格納できるタイプの変数です。 配列は @var で表し、$var[ 添字 ] という形式で各要素にアクセスしますよね。 添字は0から始まる正の整数値で、このため要素の並びが保持され、データを順次処理するのに向きます。 ハッシュは %var と表し、$var{ 添字 } という形式で各要素にアクセスします。 添字は「キー」と呼ばれる「文字列」であるため、配列とは異なり要素の並びが保持されません。 問題の $syukei{$fld}++; は、暗黙のうちに %syukei というハッシュ変数を用意し、キーが $fld である要素の値をインクリメントしています。 (本当はループ前に %syukei の使用宣言をした方がよいです。) 各要素の初期値は「未定義値(数値としては 0)」なので、上記スクリプトでは「年齢ごとの人数」をカウントしていることになります。 ハッシュの各要素を取り出すには、keys 関数を使うのが一般的です。 keys はハッシュの全てのキーをリストにして返します。 foreach $key (keys %var) { print "$key => $var{$key}\n"; } keys が返すキーの並びは内部的なものなので、これを年齢(数値)順にしたいときは sort 関数を使って次のようにします。 foreach $key (sort {$a <=> $b} keys %var) { print "$key => $var{$key}\n"; } ※詳しくは sort 関数について調べてみてください。
お礼
回答ありがとうございます。 やっと意味がわかりました。 最初は各要素の初期値は未定義値なんですね。 それでゼロがあり、 また、最初に %syukeiとして、宣言しておいたほうがよいということですね。 その場合なんですが、%syukeiの使用宣言というのは、 何をすればいいのでしょうか。 ハッシュについては、まだ勉強を始めたばかりで、 配列のほうがイメージしやすかっただけに、 キーという概念を捉えるのが非常に困難を極めておりました。 ですが、すこし光がさしてきたように思えます。
- ikspiari
- ベストアンサー率48% (29/60)
連想配列というのは、キーがユニークな値なんですね。 ですから、 @list=(20,25,24,32,28,20,28,24,20); を foreach $fld(@list){ $syukei{$fld}++; } で、連想配列に格納していくと以下のような結果になります。 $syukei{'20'} = 3; $syukei{'24'} = 2; $syukei{'25'} = 1; $syukei{'28'} = 2; $syukei{'32'} = 1; ソースの最後に以下を追加してみてください。 while ( ($key,$val) = each(%syukei) ) { print "$key=$val\n"; } 連想配列の仕組みが分かると思いますよ。 ちなみに連想配列の値は何も数値でなくても構いません。 上記ソースの%syukeiを%ENVにすると環境変数が出力されます。 参考になれば幸いです。
お礼
ありがとうございました。 ソースの最後に教えてくださった一文を加えて、 ブラウザで確認をしてみました。 連想配列とは非常に難しいというか、慣れるまでは、使いにくいですね。 でも、おかげさまで、今はしんどいですが、 もうしばらくがんばればなんとかなりそうな気もしてきました。 ご丁寧にありがとうございました。
- ikspiari
- ベストアンサー率48% (29/60)
$syukei{$fld}++; は連想配列と呼ばれるものです。 $syukeiという変数のキーに$fldが入ります。 ここでは値に++として数値を1ずつプラスしています。 @listの内容から集計結果は例えば、 $syukei{'20'} = 3; となります。 @listの配列に20が3つありますよね。 ちなみに連想配列は%で現します。 この例では、%syukeiに連想配列が格納されます。
お礼
ありがとうございます。 回答を何度も読ませていただきましたが、 まだ理解に苦しんでいます。 >$syukeiという変数のキーに$fldが入ります。 とのことですが、となると、まず、一番先頭の 20が入るということですよね。 それに、++していくのですから、 20が21になるような気がするのですが、 これは違うとは思うのですが、説明ができない状態です。 foreach文は繰り返し処理をする命令文なので、 なぜ、++を毎度してあげるのかということもわからなくなってしまいました。 一番最初の年齢の「20」というのは、初期値がゼロで、初めて出てきた段階で、++により、ゼロから1にカウントされるのでしょうか? ちぐはぐな文章になってしまいましたが、もう一度アドバイスいただけないでしょうか。 宜しくお願いします。
- nightowl
- ベストアンサー率44% (490/1101)
$syukei(集計)という変数は、おそらく年齢が現れる頻度を格納するものでしょう。 foreach ループで配列 @list の要素を順に見ていって、 20歳だったら $shukey{20} の値が一つ増えると。 >++という記号を使用していますが、これを別の書き方で >書き換えることはできないでしょうか。 $syukei{$fld} = $syukei{$fld} + 1; と同じ意味ですが、長くなるので誰もこのような書き方はしませんね。
お礼
ありがとうございます。 nightowlさんのおっしゃられるとおりで、 年齢が現れる頻度が格納されるようです。 ですので、20歳は3つとなります。 実は、何度も回答を読み直したのですが、 まだ理解できないんです。 まず、いきなり$syukeiというスカラー変数が出てくるのであれば、 $syukei= という形で入るべきではないかと思うのですが、 どうもわかりません。 また$syukei{$fld}で、$syukei{20}の場合、 $syukei{$fld}++だと、20,21,22と増えていくのではないのでしょうか?それは違うとわかっているつもりなんですが、説明しろと言われると、自分ではどういえばいいのかわからない状態です。 頭の中がぐちゃぐちゃになってしまいました。 $syukei{$fld}=$syukei{$fld}+1; と書き換えられるという意味は理解致しました。 foreachの文章の中に、 ++という演算子を用いるということがイメージしにくくて困っています。 もう一度アドバイスお願いできますでしょうか。 宜しくお願いします。
お礼
ありがとうございます。 初期化の方法、大変よくわかりました。 たしかに人のコードを読む際には、 他人がみてもよくわかるようなコードに仕上げる必要はありますよね。 まだまだ未熟ですが、perlの面白さにはまりつつあります。 がんばります。 ご丁寧にありがとうございました。