第3講 for文の学習

第8話 2次元ループ

では、準備ができましたのでいよいよプログラム上から、
2次元上にデータを入れたり、列合計、行合計、行平均などを計算させて見ましょう。
データ設定
(赤い囲いは、説明のために入れたもので実際のソフトのWindow上にはありません。)
エクセルのようにA列の1行目のセルをA1を表すことにしましょう。
A1は上図の選択セル(青いセル)です。
D1にデータを入れるときは、
dataGridView1[3,0]->Value =L"合計 ";
とします。VBAの経験者なら、Cellsを思い浮かべるでしょうが、
違いが2点あります。行と列が反対ということと、dataGridView1[*,*]の始まりが0であるのに対して
Cells(*,*)の方は1から始まります。
つまり、dataGridView1[3,0]に対応するのはCells(1,4)です。
A1はdataGridView1[0,0]に対応します。A1は1列目1行目を意味していますから、
そこから1引くとdataGridView1になります。0から始まるからです。
エクセル場合は、A1(1列目1行目)がCells(1行目,1列目)と逆になっているので慣れるまで頭が混乱します。
dataGridViewの場合はA1(1列目,1行目)が[0列目,0行目]ですから、列行はその順で対応していますが、
一番最初を1ではなく0と数えるため1個ずれるのです。
Cellsになれた方は、逆順なのでしばらくは頭が混乱してしまうのは仕方がありません。
Cellsで一回頭が混乱し、再びDataGridViewで頭が混乱します。
(尚、DataGridViewとdataGridViewと大文字と小文字が混入していますが、
Form1[デザイン]ではDataGridViewで、コード上ではdataGridViewです。
C言語は基本的に小文字から始める言語だったので、
基本的に大文字から始めるBasicをベースにするVisual Basicなどとデザインを統一したので、
不統一が生じているのです。これも混乱の原因になっていますね。)
すべての言語等で統一してくれたら、どんなにわかりやすいことでしょうか。
さて、->は『の』でした。Valueはなんでしょうか。値です。
この値は、エクセルのシートのように数字でも文字でも入れられます。
文字を入れるときはL""で囲うのは、文字の変数に文字を入れるときと同じです。
B2に数字4を入れるには、dataGridView1[1,1]->Value =4です。

さて、ここの学習のメインは、データのように2次元(平面すなわち縦と横の2方向)データをどう入れるかです。
また、1行の行合計の計算は1次元(直線=1方向))ですが、3行の処理となると横の処理に縦処理が加わりますから、
やはり2次元処理です。
2次元(縦と横の2方向)処理を行うのが、この話のメインテーマである2次元ループです。
2次元ループは、for文を入れ子式に入れることによって実現します。

では、順にプログラミングしていきましょう。
まず、行の追加
のように行を追加するプログラムからです。
実行ボタンをダブルクリックして、
#pragma endregion
   private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
           int i;

           //6行追加
           for(i=0;i<6;i++)dataGridView1->Rows->Add();

        }
};
}
とプログラミングして、F5を押しましょう。
6行追加に成功したことがわかります。
dataGridView1->Rows->Add(); は1行追加の命令です。
Rowsは行です。
そして、Add()が追加の命令です。
for文で6回繰り返すので、6行追加されるわけです。

では、皆さん1行目のD1、E1に合計、平均を入れるコードを加えてください。
確認
答えは、30行下です。































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

           //6行追加
           for(i=0;i<6;i++)dataGridView1->Rows->Add();

          //縦表題
           dataGridView1[3,0]->Value =L"合計 ";
           dataGridView1[4,0]->Value =L"平均 ";

        }
};
}
次に、列見出しA5,A6に合計、平均と入れるコードを加えてください。
解答例は、30行下。








































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

           //6行追加
           for(i=0;i<6;i++)dataGridView1->Rows->Add();

          //縦表題
           dataGridView1[3,0]->Value =L"合計 ";
           dataGridView1[4,0]->Value =L"平均 ";

          //横表題
          dataGridView1[0,4]->Value =L"合計 ";
          dataGridView1[0,5]->Value =L"平均 ";

        }
};
}

次にいよいよ、2次元データデータの入力です。
これはいきなり、考えてくださいといっても無理ですからプログラミング例を表示してから解説します。
#pragma endregion
   private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
           int i;

           //6行追加
           for(i=0;i<6;i++)dataGridView1->Rows->Add();

          //縦表題
           dataGridView1[3,0]->Value =L"合計 ";
           dataGridView1[4,0]->Value =L"平均 ";

          //2次元データ作成
         for(i=1;i<4;i++){
           for(j=1;j<3;j++){
             dataGridView1[j,i]->Value =2*i+j+1;
           }
         }


        }
};
}
ピンクの部分が2次元ループです。for文が入れ子式に入っています。
入れ子式に2重なら2次元、入れ子式に3重なら3次元、入れ子式に4重なら4次元というわけです。
因みに私の作った数独問題作成ソフトは、場合によっては2万次元ループを遙かに超えています。
魔方陣作ソフトによっては、軽く100万次元を超えているものもあります。
dataGridView1[j,i]のjは列、iは行に対応しています。
2次元だとトレースもかなり難しくなりますが、
トレースしてみましょう。
jとiは次の表の紺の数字の通りに動いていきます。

  1 2
   
1
2
3

1→2→3→4→5→6
理由は、次のように変化していくからです。
T i=1のとき
   j=1j=2
U i=2のとき
  j=1j=2
V i=3のとき
   j=1j=2





具体的に動きを追ってみましょう。
dataGridView1[j,i]->Value =2*i+j+1;は
T i=1の場合
  @ j=1のとき    
    dataGridView1[1,1]->Value =2*1+1+1;から
結果
    B2は4となります。
  A j=2のとき    
    dataGridView1[2,1]->Value =2*1+2+1;から
    C2は5となります。
U i=2の場合
  @ j=1のとき    
    dataGridView1[1,2]->Value =2*2+1+1;から
    B3は6となります。
  A j=2のとき    
    dataGridView1[2,2]->Value =2*2+2+1;から
    C3は7となります。
V i=3の場合
  @ j=1のとき    
    dataGridView1[1,3]->Value =2*3+1+1;から
    B4は8となります。
  A j=2のとき    
    dataGridView1[2,3]->Value =2*3+2+1;から
    C4は9となります。


では、今話も大分長くなりました。
次に、行の合計と平均、列の合計と平均を出すプログラミングを考えてみましょう。
ただし、DataGridViewから値を取得するときには、例えば
int w;
w=dataGridView1[1,1]->Value;
とするとエラーします。
変数の値をdataGridView1に渡すときは、
int w;
w=10;
dataGridView1[1,1]->Value=w;
でいいのですが、DataGridViewから値を取得してそれを変数に収納するには、
キャスト(データ型の変換)をしてやらなければなりません。
プログラム上の変数で扱えるint型にするには、
w=(int)(dataGridView1[1,1]->Value);
としなければならないのです。
(int)(*)は*を変数で扱えるint型に強制的に変更する命令です。
C++言語の面倒くさいところなのですが、
同じ整数でありながら、DataGridView上の整数とプログラム上で扱えるint(整数)型は違うのです。
dataGridView1[1,1]->Value=w; は大丈夫なのに逆はだめというのはおそらく、
DataGridViewに値を入れるときには、自動的にキャストをしてくれますが、
逆は、自動的にはしてくれないので、プログラム上で意識的にキャストしなければならないということだと思います。
(どうしてかは、私にもわかりません。前にも言いましたが、完全に理解しないと前へ進めないという姿勢は、
プログラムの勉強では避けなければなりません。意図したとおりに動けばいい、という考え方をしてください。)




第7話へ 第9話へ

025


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

数学研究室に戻る