Perlの参考書で配列が説明されることはありますが、多くの場合、1次元配列になっています。2次元以上のデータを扱うには、リファレンスを利用するのですが、以下、実例を示して説明します。具体的には、「@sum」という配列が3次元配列の場合、個々の要素は、
$sum[0][1][2]
のように表記します。リファレンスを利用するため、正確には
$sum[0]->[1]->[2]
と表記すべきですが、通常は省略して表記されます。
下記のスクリプトには示していませんが、配列全体を初期化するには、
@sum = ()
のように「カッコ」を利用します。
@sum = undef
を行うと、「push」などの命令では、配列の最初の列が利用できなくなるので注意が必要です。また、ゼロクリアするには、「for」文を利用して行います。三次元配列であれば、「for」文を3回繰り返し、その中で
for ($i = 0; $i <=3; $i++) { for ($j = 0; $j <=4; $j++) { for ($k = 0; $k <=3; $k++) { $sum[$i][$j][$k] = 0; } } }
のように行います。
最低点を求めるために、100点満点として、初期値に「100」を設定しています。満点が100点以外の場合は修正が必要ですが、満点を設定しておくことで、入力値がこれより小さい場合に値を置き換える作業を繰り返していけば、最低点が求まります。最高点についても同様に初期値に「0」を設定し入力値がこれより大きい場合は、最高点を置き換える作業を繰り返して、最高点を求めます。
最高点や最低点はそれぞれのクラスごとに異なるだけでなく、全体で見たときにも必要になりますので、別個に集計を行います。
# tabulation.pl # 内容 : クラス別科目別成績データ集計 # Copyright (c) 2002-2011 Mitsuo Minagawa, All rights reserved. # (minagawa@fb3.so-net.ne.jp) # 使用方法 : c:\>perl tabulation.pl # open(IN1,"input.txt"); open(OUT1,">total.txt"); # #入力データ:以下の5項目 # # クラス,出席番号,氏名,科目コード,点数 # #集計用データ: # $sum[0-3][0-3][0-4] # 1次元目=>1組:0、2組:1、3組:2、合計:3の4項目 # 2次元目=>国語から社会までの5科目 # 国語:01、算数:02、理科:03、社会:04、英語:05 # 3次元目=>生徒数、最高点、最低点、平均点の4項目 # #テーブルの初期化 #最低点の初期値として、100点を設定する。 # for ($i = 0; $i <=3; $i++) { for ($j = 0; $j <=4; $j++) { for ($k = 0; $k <=3; $k++) { if ($k == 2) { $sum[$i][$j][$k] = 100; #最低点の初期値 } else { $sum[$i][$j][$k] = 0; } } } } # #メイン処理 # while($line1 = <IN1>) { chomp($line1); @in1 = split('\t',$line1); # #クラスの振り分け # if ($in1[0] eq "1") { #"1"は1組 $i = 0; } elsif ($in1[0] eq "2") { #"2"は2組 $i = 1; } elsif ($in1[0] eq "3") { #"3"は3組 $i = 2; } # #科目の振り分け # if ($in1[3] eq "01") { #国語 $j = 0; } elsif ($in1[3] eq "02") { #算数 $j = 1; } elsif ($in1[3] eq "03") { #理科 $j = 2; } elsif ($in1[3] eq "04") { #社会 $j = 3; } elsif ($in1[3] eq "05") { #英語 $j = 4; } # # #生徒数 # $sum[$i][$j][0]++; #クラス別の生徒数 $sum[3][$j][0]++; #全クラスの生徒数 # #最高点(初期値:0) # if ($sum[$i][$j][1] < $in1[4]) { $sum[$i][$j][1] = $in1[4]; #クラス別科目別の最高点 } if ($sum[3][$j][1] < $in1[4]) { $sum[3][$j][1] = $in1[4]; #全クラスの科目別の最高点 } # #最低点(初期値:100) # if ($sum[$i][$j][2] > $in1[4]) { $sum[$i][$j][2] = $in1[4]; #クラス別科目別の最低点 } if ($sum[3][$j][2] > $in1[4]) { $sum[3][$j][2] = $in1[4]; #全クラスの科目別の最低点 } # #平均点(初期値:0)(最後に生徒数で割る) # $sum[$i][$j][3] += $in1[4]; #クラス別科目別の合計点 $sum[3][$j][3] += $in1[4]; #全クラスの科目別の合計点 } # #平均点算出 # for ($i = 0; $i <=3; $i++) { for ($j = 0; $j <=4; $j++) { # # クラス別科目別で生徒数がゼロなら、最高点と最低点、平均点をブランクにする。 # それ以外は、クラス別科目別の平均点を算出する。 # if ($sum[$i][$j][0] == 0) { $sum[$i][$j][1] = ""; #クラス別科目別の最高点 $sum[$i][$j][2] = ""; #クラス別科目別の最低点 $sum[$i][$j][3] = ""; #クラス別科目別の平均点 } else { $sum[$i][$j][3] = sprintf("%5.2f",$sum[$i][$j][3] / $sum[$i][$j][0]); } } } # #成績データ出力 # # 各列の項目 @out1_title = ("項目","国語","算数","理科","社会","英語"); # # 各行の項目 @out1_item = ("生徒数","最高点","最低点","平均点"); # for ($i = 0; $i <=3; $i++) { for ($k = 0; $k <=3; $k++) { if ($k == 0) { if ($i == 0) { print OUT1 "1組\n"; } elsif ($i == 1) { print OUT1 "2組\n"; } elsif ($i == 2) { print OUT1 "3組\n"; } elsif ($i == 3) { print OUT1 "総合計\n"; } $out1 = join("\t",@out1_title); #クラス名等出力 print OUT1 "$out1\n"; } @out1 = (); push(@out1,$out1_item[$k]); #各行の項目名セット for ($j = 0; $j <=4; $j++) { push(@out1,$sum[$i][$j][$k]); #各行の値セット } $out1 = join("\t",@out1); print OUT1 "$out1\n"; } } close(IN1); close(OUT1);
1 01 青木 昇 01 67 1 01 青木 昇 02 40 1 01 青木 昇 03 86 1 01 青木 昇 04 83 1 01 青木 昇 05 95 (中 略) 3 36 横川 宗治 01 31 3 36 横川 宗治 02 75 3 36 横川 宗治 03 81 3 36 横川 宗治 04 30 3 36 横川 宗治 05 88
1組 項目 国語 算数 理科 社会 英語 生徒数 35 35 35 35 35 最高点 98 99 100 99 100 最低点 27 26 28 31 30 平均点 60.23 63.51 59.34 66.20 66.54 2組 項目 国語 算数 理科 社会 英語 生徒数 36 36 36 36 36 最高点 100 100 97 100 98 最低点 25 25 25 25 29 平均点 59.14 60.28 59.86 62.64 62.94 3組 項目 国語 算数 理科 社会 英語 生徒数 36 36 36 36 36 最高点 99 99 99 100 100 最低点 25 31 27 27 26 平均点 62.81 67.72 65.14 61.11 60.39 総合計 項目 国語 算数 理科 社会 英語 生徒数 107 107 107 107 107 最高点 100 100 100 100 100 最低点 25 25 25 25 26 平均点 60.73 63.84 61.47 63.29 63.26