■Windows版Perlの細道・けもの道

■ナビゲータ

[南北館(最初のメニュー)]

  1. [Windows版Perlの細道・けもの道]
    1. [1.準備編]
    2. [2.基本編]
    3. [3.応用編]
      1. [3-1.固定長データとCSVデータとの変換]
      2. [3-2.重複データの処理]
      3. [3-3.フォルダ内の一括処理]
      4. [3-4.1つのファイルを複数のファイルに分割する]
      5. [3-5.文字コードの変換]
      6. [3-6.半角全角変換]
      7. [3-7.多次元配列の処理]
      8. [3-9.その他]
    4. [スクリプトと入力データのサンプル]
rubyではどう処理する?
同じことをrubyではこうしています。

3.応用編

3-7.多次元配列の処理

3-7-1.多次元配列の処理(最高点・最低点・平均点の計算)

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   
    



Copyright (c) 2004-2013 Mitsuo Minagawa, All rights reserved.