第5講 配列の学習

第9話 3次元配列の利用による年間成績一覧表の作成の解説その1

解答例
#pragma endregion
   private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
           int i,j,k,max,min,w;

           //189行加える
           for(i=0;i<188;i++)dataGridView1->Rows->Add();

           for(i=0;i<4;i++){
             //1行目 見出し
             if(i==0)dataGridView1[0,47*i]->Value =L"1学期";
             if(i==1)dataGridView1[0,47*i]->Value =L"2学期";
             if(i==2)dataGridView1[0,47*i]->Value =L"3学期";
             if(i==3)dataGridView1[0,47*i]->Value =L"1年間";

             //2行目 列見出し
             dataGridView1[0,1+47*i]->Value =L"番号 ";
             dataGridView1[1,1+47*i]->Value =L"国語 ";
             dataGridView1[2,1+47*i]->Value =L"社会 ";
             dataGridView1[3,1+47*i]->Value =L"数学 ";
             dataGridView1[4,1+47*i]->Value =L"理科 ";
             dataGridView1[5,1+47*i]->Value =L"社会 ";
             dataGridView1[6,1+47*i]->Value =L"合計 ";
             dataGridView1[7,1+47*i]->Value =L"平均 ";
             dataGridView1[8,1+47*i]->Value =L"最高点 ";
             dataGridView1[9,1+47*i]->Value =L"最低点 ";
             dataGridView1[10,1+47*i]->Value =L"順位 ";
             dataGridView1[11,1+47*i]->Value =L"合否 ";
             dataGridView1[12,1+47*i]->Value =L"講評  ";

             //43行から46行 行見出し
             dataGridView1[042+47*i]->Value =L"合計 ";
             dataGridView1[0,43+47*i]->Value =L"平均 ";
             dataGridView1[0,44+47*i]->Value =L"最高点 ";
             dataGridView1[0,45+47*i]->Value =L"最低点 ";
           }

           //出席番号とランダムデータ発生
           int a[4][40][7];
           for(i=0;i<3;i++){
             for(j=1;j<=40;j++){
               a[i][j-1][0]=j;
             }
             for(j=1;j<=40;j++){
               for(k=1;k<=5;k++){
                 a[i][j-1][k]=rand()%101;
               }
             }
           }

           //出席番号とデータの表示
           for(i=0;i<=2;i++){
             for(j=1;j<=40;j++){
               dataGridView1[0,47*i+j+1]->Value=a[i][j-1][0];
             }
             for(j=1;j<=40;j++){
               for(k=1;k<=5;k++){
                 dataGridView1[k,47*i+j+1]->Value=a[i][j-1][k];
               }
             }
           }

           //各生徒の合計・平均の算出と表示
           for(i=0;i<=2;i++){
             for(j=1;j<=40;j++){
               a[i][j-1][6]=0;
               for(k=1;k<=5;k++){
                 a[i][j-1][6]=a[i][j-1][6]+a[i][j-1][k];
               }
               dataGridView1[6,47*i+j+1]->Value=a[i][j-1][6];
               dataGridView1[7,47*i+j+1]->Value=(double)(a[i][j-1][6])/5;
             }
           }

           //各生徒の最高点・最低点の算出と表示
           for(i=0;i<=2;i++){
             for(j=1;j<=40;j++){
               max=0;min=100;
               for(k=1;k<=5;k++){
                 if(a[i][j-1][k]>max)max=a[i][j-1][k];
                 if(a[i][j-1][k]<min)min=a[i][j-1][k];
               }
               dataGridView1[8,47*i+j+1]->Value=max;
               dataGridView1[9,47*i+j+1]->Value=min;
             }

           
}

                       ・
                       ・
                       ・

         }

};
}

本日は、『//各生徒の合計・平均の算出と表示』までを解説しましょう。
最初に

           //189行加える
           for(i=0;i<188;i++)dataGridView1->Rows->Add();

           for(i=0;i<4;i++){
             //1行目 見出し
             if(i==0)dataGridView1[0,47*i]->Value =L"1学期";
             if(i==1)dataGridView1[0,47*i]->Value =L"2学期";
             if(i==2)dataGridView1[0,47*i]->Value =L"3学期";
             if(i==3)dataGridView1[0,47*i]->Value =L"1年間";

             //2行目 列見出し
             dataGridView1[0,1+47*i]->Value =L"番号 ";
             dataGridView1[1,1+47*i]->Value =L"国語 ";
             dataGridView1[2,1+47*i]->Value =L"社会 ";
             dataGridView1[3,1+47*i]->Value =L"数学 ";
             dataGridView1[4,1+47*i]->Value =L"理科 ";
             dataGridView1[5,1+47*i]->Value =L"社会 ";
             dataGridView1[6,1+47*i]->Value =L"合計 ";
             dataGridView1[7,1+47*i]->Value =L"平均 ";
             dataGridView1[8,1+47*i]->Value =L"最高点 ";
             dataGridView1[9,1+47*i]->Value =L"最低点 ";
             dataGridView1[10,1+47*i]->Value =L"順位 ";
             dataGridView1[11,1+47*i]->Value =L"合否 ";
             dataGridView1[12,1+47*i]->Value =L"講評  ";

             //43行から46行 行見出し
             dataGridView1[042+47*i]->Value =L"合計 ";
             dataGridView1[0,43+47*i]->Value =L"平均 ";
             dataGridView1[0,44+47*i]->Value =L"最高点 ";
             dataGridView1[0,45+47*i]->Value =L"最低点 ";
           }
を解説しましょう。この部分で何をしているかと申しますと、

実行結果例
yt
ge
行を作り、そこに見出しを入れています。
for(i=0;i<4;i++)となっていますので、
i=0,1,2,3 と同じことが4回繰り返されます。
その結果、1学期、2学期、3学期、1年間
afgxasawerfwetw
それぞれの見出しが入ります。
注目は、例えばdataGridView1[0,42+47*i]->Value =L"合計 "; の+47*iの部分です。
gsd
学期間の『合計』の位置が47行ずれています。
なので、i=0,1,2,3 とすると、
42+47×0=42
42+47×1=89
42+47×2=136
42+47×0=183
となります。
DataGridView1(*,0)は1行目ですから、43行目・90行目・137行目・184行目に『合計』が表示されることになります。
その他についてもすべて同じです。
例えば、dataGridView1[0,1+47*i]->Value =L"番号 ";についてみると、
『番号』も47行ごとに表示させています。
47行という数字は、生徒数40から40行、
見出しと列見出しer2行、
行見出しss4行、学期間の空白行hdfr1行の合計です。
40+2+4+1=47
それぞれ47行ごとに表示させたいとき、42+47*i のようにすればよいわけです。


次に、
           //出席番号とランダムデータ発生
           int a[4][40][7];
           for(i=0;i<3;i++){
             for(j=1;j<=40;j++){
               a[i][j-1][0]=j;
             }
             for(j=1;j<=40;j++){
               for(k=1;k<=5;k++){
                 a[i][j-1][k]=rand()%101;
               }
             }
           }
を解説しましょう。最初のint a[4][40][7]; で3次元配列を用意しています。
[4]は、1学期・2学期・3学期・1年間の4つに対応します。
[4]とした場合許される添え字はa[0],a[1],a[2],a[3]まででしたね。
VBならa(4)まで許されましたが、VC++でa[3]までであることに注意して下さい。
次の[40]は、生徒数40に対応しています。
最後の[7]は、出席番号・国語・社会・数学・理科・英語・合計の7つに対応しています。
平均までを対象にしなかったのは、平均だけ整数でないからです。
こちらは実数型になります。
キャストなどをして対象にする方法も考えられますが、面倒なので合計までを配列で扱い処理することにしました。
             for(j=1;j<=40;j++){
               a[i][j-1][0]=j;
             }

             for(j=0;j<=39;j++){
               a[i][j][0]=j+1;
             }
としてもいいですが、jを出席番号に対応させた方がわかりやすいと考え前者を選びました。
ですが、この辺は各自の好みです。ご自分がわかりやすい方を選んでください。
この3行では、3次元配列をa[学期等][行][列]と表現するとすれば、各学期の0列目の0行目から39行目まで順に出席番号を入れています。

             for(j=1;j<=40;j++){
               for(k=1;k<=5;k++){
                 a[i][j-1][k]=rand()%101;
               }
             }
では、100点以下のランダムデータを配列に収納しています。
rand()は、10万以下ぐらい(ごめんなさい正確には知りません)の乱数を発生させます。
*%101は*を101で割ったときの余りを出すものです。
ですから、rand()%101 で100以下のランダムデータができるのです。

           //出席番号とデータの表示
           for(i=0;i<=2;i++){
             for(j=1;j<=40;j++){
               dataGridView1[0,47*i+j+1]->Value=a[i][j-1][0];
             }
             for(j=1;j<=40;j++){
               for(k=1;k<=5;k++){
                 dataGridView1[k,47*i+j+1]->Value=a[i][j-1][k];
               }
             }
           }
では、配列に収まっている出席番号と各教科のランダムデータをdataGridView1に表示させています。
dataGridView1[0,47*i+j+1]->Value=a[i][j-1][0]; は3次元配列を2次元配列に対応させています。
その際の味噌は
47*i+j+1です。
47*i+j+1は、j+1+47*i と同じです。

実は、3次元データは、2次元でも1次元でも表現できます。
言い換えると、3次元配列は、2次元配列や1次元配列に対応させることができます。

同様に、2次元配列は1次元配列で表現できます。
例えば、
int a[3][4],b[12],i,j;
for(i=0;i<12;i++)b[i]=rand()%101;
for(i=0;i<3;i++){
  for(j=0;j<4;j++){
    a[i][j]=b[4*i+j];
  }
}
とプログラミングすれば、1次元配列b[12]のランダムデータを2次元配列a[3][4]に収納させたことになります。
a[i][j]=b[10*i+j]; の対応を具体的に見てみましょう。
a[0][0]=b[0],a[0][1]=b[1],a[0][2]=b[2],a[0][3]=b[3],
a[1][0]=b[4],a[1][1]=b[5],a[1][2]=b[6],a[1][3]=b[7],
a[2][0]=b[8],a[2][1]=b[9],a[2][1]=b[10],a[2][3]=b[11]
2次元配列a[3][4]の12(3×4)個の変数と1次元配列b[12]の12個の変数がきれいに対応しています。
ここでの味噌は、4*i+jです。動きを表にすると、

i j 4*i+j
0 0 0
0 1 1
0 2 2
0 3 3
1 0 4
1 1 5
1 2 6
1 3 7
2 0 8
2 1 9
2 2 10
2 3 11


例えば、i=2,j=3なら
4*i+j=4×2+3=11
です。
4*i+jの4は、 a[3][4]の4に対応しています。

for(i=0;i<3;i++){
  for(j=0;j<4;j++){
    a[i][j]=rand()%101;
  }
}
として、それをb[12]に収めたいなら、
for(i=0;i<3;i++){
  for(j=0;j<4;j++){
    b[4*i+j]=a[i][j];
  }
}
このように2次元配列を1次元配列に、
1次元配列を2次元配列に対応させることができます。
すなわち、1次元配列と2次元配列は相互に対応させることができるのです。


dataGridView1[k,47*i+j+1]->Value=a[i][j-1][k];
においては3次元データを2次元配列に代入しています。

47*i+j+1と[i][j-1]が対応します。
今の例の
4*i+jと[i][j]の対応と同様です。4*iの4はa[3][4]の4でした。
dataGridView1の場合は、a[4][40][7]の40に見出しと列見出し2行、行見出し4行、空白行1行を加えた47です。
見出しと列見出し2行、行見出し4行、空白行1行がなければ、a[4][40][7]の40にきれいに対応するのです。

尚、参考までに述べておくと
for(i=0;i<3;i++){
  for(j=0;j<4;j++){
    b[4*i+j]=a[i][j];
  }
}
は、
for(i=0;i<12;i++)b[i]=a[i/4][i%4];
でも実現できます。
iはint型ですからi/4の小数部分は切り捨てられます。
例えば、i=7なら7/4=1です。
また、i%4は7%4=3です。
ですから
b[7]=a[1][3]です。上の表で対応が正しいことをご確認ください。


本日の最後
           //各生徒の合計・平均の算出と表示
           for(i=0;i<=2;i++){
             for(j=1;j<=40;j++){
               a[i][j-1][6]=0;
               for(k=1;k<=5;k++){
                 a[i][j-1][6]=a[i][j-1][6]+a[i][j-1][k];
               }
               dataGridView1[6,47*i+j+1]->Value=a[i][j-1][6];
               dataGridView1[7,47*i+j+1]->Value=(double)(a[i][j-1][6])/5;
             }
           }


では、合計を計算して合計と平均を表示しています。
a[i][j-1][6]が合計です。
a[i][j-1][6]=0; を忘れないでください。
これは初期化です。

           //各生徒の最高点・最低点の算出と表示
           for(i=0;i<=2;i++){
             for(j=1;j<=40;j++){
               max=0;min=100;
               for(k=1;k<=5;k++){
                 if(a[i][j-1][k]>max)max=a[i][j-1][k];
                 if(a[i][j-1][k]<min)min=a[i][j-1][k];
               }
               dataGridView1[8,47*i+j+1]->Value=max;
               dataGridView1[9,47*i+j+1]->Value=min;
             }
では各生徒の最高点・最低点を計算し表示しています。ここでも47*i+j+1が理解できれば難しくありません。




第8話へ 第10話へ

025


vc++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ

数学研究室に戻る