第8講 Functionプロシージャ

第4話 成績一覧表作成ソフトのプロシージャによる改良その2
前話問題解答例
Public Class Form1
   Dim a(3, 39, 6) As Integer
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

     '187行追加
     f1()

     '見出しを入れる
     f2()

     '出席番号とランダムデータの発生
     f3()

     '出席番号とランダムデータをDataGridViewに表示させる
     f4()

     '各学期合計値・平均値の算出・表示
     f5()

     '各学期各生徒の最高点・最低点の算出・表示
     f6()

     '各学期合否・講評の算出・表示
     f7()

     '各学期各教科の合計・平均の算出・表示
     f8()

     '各学期各教科の最高点・算出の算出・表示
     f9()

     '各学期の並び替え
     f10()

     '各学期順位付け
     f11()

     '各学期出席番号順並び替え
     f12()

   End Sub

   '187行追加
   Sub f1()
     Dim i As Integer
     For i = 1 To 187
       DataGridView1.Rows.Add()
     Next
   End Sub

   '見出しを入れる
   Sub f2()
     Dim i As Integer
     For i = 0 To 3
       '見出しを入れる
       If i = 0 Then DataGridView1(0, 47 * i).Value = "1学期"
       If i = 1 Then DataGridView1(0, 47 * i).Value = "2学期"
       If i = 2 Then DataGridView1(0, 47 * i).Value = "3学期"
       If i = 3 Then DataGridView1(0, 47 * i).Value = "1年間"

       '列見出しを入れる。
       DataGridView1(0, 1 + 47 * i).Value = "番号 "
       DataGridView1(1, 1 + 47 * i).Value = "国語 "
       DataGridView1(2, 1 + 47 * i).Value = "社会 "
       DataGridView1(3, 1 + 47 * i).Value = "数学 "
       DataGridView1(4, 1 + 47 * i).Value = "理科 "
       DataGridView1(5, 1 + 47 * i).Value = "英語 "
       DataGridView1(6, 1 + 47 * i).Value = "合計 "
       DataGridView1(7, 1 + 47 * i).Value = "平均 "
       DataGridView1(8, 1 + 47 * i).Value = "最高点"
       DataGridView1(9, 1 + 47 * i).Value = "最低点"
       DataGridView1(10, 1 + 47 * i).Value = "順位 "
       DataGridView1(11, 1 + 47 * i).Value = "合否 "
       DataGridView1(12, 1 + 47 * i).Value = "講評 "

       '行見出し
       DataGridView1(0, 42 + 47 * i).Value = "合計 "
       DataGridView1(0, 43 + 47 * i).Value = "平均 "
       DataGridView1(0, 44 + 47 * i).Value = "最高点"
       DataGridView1(0, 45 + 47 * i).Value = "最低点"
     Next
   End Sub

   '出席番号とランダムデータの発生
   Sub f3()
     Dim k As Integer
     For i = 0 To 3
       For j = 1 To 40
         a(i, j - 1, 0) = j
       Next
     Next
     For i = 0 To 2
       For j = 1 To 40
         For k = 1 To 5
           a(i, j - 1, k) = Int(101 * Rnd())
         Next
       Next
     Next
   End Sub

   '出席番号とランダムデータをDataGridViewに表示させる
   Sub f4()
     Dim i As Integer, j As Integer
     For i = 0 To 3
       For j = 1 To 40
         DataGridView1(0, i * 47 + j + 1).Value = a(i, j - 1, 0)
       Next
     Next
     For i = 0 To 2
       For j = 1 To 40
         For k = 1 To 5
           DataGridView1(k, i * 47 + j + 1).Value = a(i, j - 1, k)
         Next
       Next
     Next
   End Sub

   '各学期合計値・平均値の算出・表示
   Sub f5()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 1 To 40
         a(i, j - 1, 6) = 0
         For k = 1 To 5
           a(i, j - 1, 6) = a(i, j - 1, 6) + a(i, j - 1, k)
         Next
         DataGridView1(6, i * 47 + j + 1).Value = a(i, j - 1, 6)
         DataGridView1(7, i * 47 + j + 1).Value = a(i, j - 1, 6) / 5
       Next
     Next
   End Sub

   '各学期各生徒の最高点・最低点の算出・表示
   Sub f6()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 1 To 40
         DataGridView1(8, i * 47 + j + 1).Value = g61(i, j)
         DataGridView1(9, i * 47 + j + 1).Value = g62(i, j)
       Next
     Next
   End Sub
   Function g61(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim max As Integer
     max = 0
     For i = 1 To 5
       If a(p, q - 1, i) > max Then max = a(p, q - 1, i)
     Next
     Return max
   End Function
   Function g62(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim min As Integer
     min = 100
     For i = 1 To 5
       If a(p, q - 1, i) < min Then min = a(p, q - 1, i)
     Next
     Return min
   End Function

  
   '各学期合否・講評の算出・表示
   Sub f7()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 1 To 40
         If a(i, j - 1, 6) >= 250 Then DataGridView1(11, i * 47 + j + 1).Value = "合格"
         If a(i, j - 1, 6) < 250 Then DataGridView1(11, i * 47 + j + 1).Value = "不合格"
       Next
       For j = 1 To 40
         If a(i, j - 1, 6) >= 350 Then DataGridView1(12, i * 47 + j + 1).Value = "上位合格です。"
         If a(i, j - 1, 6) < 350 And a(i, j - 1, 6) >= 280 Then DataGridView1(12, i * 47 + j + 1).Value = "余裕で合格です。"
         If a(i, j - 1, 6) < 280 And a(i, j - 1, 6) >= 250 Then DataGridView1(12, i * 47 + j + 1).Value = "ぎりぎり合格です。"
         If a(i, j - 1, 6) < 250 And a(i, j - 1, 6) >= 230 Then DataGridView1(12, i * 47 + j + 1).Value = "合格まで後一歩です。"
         If a(i, j - 1, 6) < 230 Then DataGridView1(12, i * 47 + j + 1).Value = "よく勉強して再挑戦!"
       Next
     Next
   End Sub

   '各学期各教科の合計・平均の算出・表示
   Sub f8()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 1 To 6
         DataGridView1(j, i * 47 + 42).Value = g8(i, j)
         DataGridView1(j, i * 47 + 43).Value = g8(i, j) / 40
       Next
       DataGridView1(7, i * 47 + 42).Value = DataGridView1(6, i * 47 + 42).Value / 5
       DataGridView1(7, i * 47 + 43).Value = DataGridView1(7, i * 47 + 42).Value / 40
     Next
   End Sub
   Function g8(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim w As Integer
     w = 0
     For i = 1 To 40
       w = w + a(p, i - 1, q)
     Next
     Return w
   End Function


   '各学期各教科の最高点・算出の算出・表示
   Sub f9()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 1 To 6
         DataGridView1(j, i * 47 + 44).Value = g91(i, j)
         DataGridView1(j, i * 47 + 45).Value = g92(i, j)
       Next
     Next
   End Sub
   Function g91(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim max As Integer
     max = 0
     For i = 1 To 40
       If a(p, i - 1, q) > max Then max = a(p, i - 1, q)
     Next
     Return max
   End Function
   Function g92(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim min As Integer
     min = 0
     For i = 1 To 40
       If a(p, i - 1, q) < min Then min = a(p, i - 1, q)
     Next
     Return min
   End Function


   '各学期の並び替え
   Sub f10()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 40 To 2 Step -1
         h10(i, j, g10(i, j))
       Next
     Next
   End Sub
   Function g10(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim min, bn, i, w As Integer
     min = 500
     For i = 1 To q
       If a(p, i - 1, 6) < min Then
         min = a(p, i - 1, 6)
         bn = i
       End If
     Next
     Return bn
   End Function
   Sub h10(ByVal p As Integer, ByVal q As Integer, ByVal bn As Integer)
     Dim i As Integer, w As Integer, w1 As String
     For i = 0 To 6
       w = a(p, bn - 1, i)
       a(p, bn - 1, i) = a(p, q - 1, i)
       a(p, q - 1, i) = w
     Next
     For i = 0 To 12
       w1 = DataGridView1(i, p * 47 + bn + 1).Value
       DataGridView1(i, p * 47 + bn + 1).Value = DataGridView1(i, p * 47 + q + 1).Value
       DataGridView1(i, p * 47 + q + 1).Value = w1
     Next
   End Sub


   '各学期順位付け
   Sub f11()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 1 To 40
         DataGridView1(10, i * 47 + j + 1).Value = j
       Next
       For j = 2 To 40
         If a(i, j - 1, 6) = a(i, j - 2, 6) Then DataGridView1(10, i * 47 + j + 1).Value = DataGridView1(10, i * 47 + j).Value
       Next
     Next
   End Sub

   '各学期出席番号順並び替え
   Sub f12()
     Dim i As Integer, j As Integer
       For i = 0 To 2
         For j = 40 To 2 Step -1
           h12(i, j, g12(i, j))
         Next
       Next
   End Sub
   Function g12(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim i As Integer, bn As Integer, max As Integer
     max = 0
     For i = 1 To q
       If a(p, i - 1, 0) > max Then
         max = a(p, i - 1, 0)
         bn = i
       End If
     Next
     Return bn
   End Function
   Sub h12(ByVal p As Integer, ByVal q As Integer, ByVal bn As Integer)
     Dim i As Integer, w As Integer, w1 As String
     For i = 0 To 6
       w = a(p, bn - 1, i)
       a(p, bn - 1, i) = a(p, q - 1, i)
       a(p, q - 1, i) = w
     Next
     For i = 0 To 12
       w1 = DataGridView1(i, p * 47 + bn + 1).Value
       DataGridView1(i, p * 47 + bn + 1).Value = DataGridView1(i, p * 47 + q + 1).Value
       DataGridView1(i, p * 47 + q + 1).Value = w1
     Next
   End Sub

End Class


Funcitonプロシージャを利用できそうなところだけ、Functionプロシージャとして独立させました。
例えば、
   '各学期各教科の最高点・算出の算出・表示
   Sub f9()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 1 To 6
         DataGridView1(j, i * 47 + 44).Value = g91(i, j)
         DataGridView1(j, i * 47 + 45).Value = g92(i, j)
       Next
     Next
   End Sub
   Function g91(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim max As Integer
     max = 0
     For i = 1 To 40
       If a(p, i - 1, q) > max Then max = a(p, i - 1, q)
     Next
     Return max
   End Function
   Function g92(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim min As Integer
     min = 0
     For i = 1 To 40
       If a(p, i - 1, q) < min Then min = a(p, i - 1, q)
     Next
     Return min
   End Function

をご覧になればおわかりのように、g91とg92がそれぞれ最高点と最低点を算出するFunctionプロシージャということで、
   Sub f9()
     Dim i As Integer, j As Integer
     For i = 0 To 2
       For j = 1 To 6
         DataGridView1(j, i * 47 + 44).Value = g91(i, j) '最高点算出
         DataGridView1(j, i * 47 + 45).Value = g92(i, j) '最低点算出
       Next
     Next
   End Sub
の部分が
    '各学期各教科の最高点・算出の算出・表示
     For i = 0 To 2
      For j = 1 To 6
        max = 0
        min = 500
        For k = 1 To 40
          If a(i, k - 1, j) > max Then max = a(i, k - 1, j)
          If a(i, k - 1, j) < min Then min = a(i, k - 1, j)
        Next
        DataGridView1(j, i * 47 + 44).Value = max
        DataGridView1(j, i * 47 + 45).Value = min
      Next
    Next
と比べてすっきりしました。3次元ループが2次元ループに落ちているからです。
各プロシージャが次元を分担することによって、
各プロシージャ内の次元を落とすことが出来るのです。
2次元と1次元にしましたがもちろんすべて1次元にすることも出来ます。
では皆さん、'各学期各教科の最高点・算出の算出・表示をすべて1次元にすることに挑戦されてください。
解答例は、30行下。

























解答例
   '各学期各教科の最高点・算出の算出・表示
   Sub f9()
     Dim i As Integer
     For i = 0 To 2
       g90(i)
     Next
   End Sub
   Sub g90(ByVal p As Integer)
     For i = 1 To 6
       DataGridView1(i, p * 47 + 44).Value = g91(p, i)
       DataGridView1(i, p * 47 + 45).Value = g92(p, i)
     Next
   End Sub
   Function g91(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim max As Integer
     max = 0
     For i = 1 To 40
       If a(p, i - 1, q) > max Then max = a(p, i - 1, q)
     Next
     Return max
   End Function
   Function g92(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim min As Integer
     min = 0
     For i = 1 To 40
       If a(p, i - 1, q) < min Then min = a(p, i - 1, q)
     Next
     Return min
   End Function
こうすると
   Sub f9()
     Dim i As Integer
     For i = 0 To 2
       g90(i)
     Next
   End Sub
の仕組みがはっきりします。
iは0,1,2と動きますが、これはそれぞれ1学期、2学期、3学期に対応します。
つまり、1次元ループの役割は各学期処理であると、
一目でわかりやすくなりました。
    '各学期各教科の最高点・算出の算出・表示
     For i = 0 To 2
      For j = 1 To 6
        max = 0
        min = 500
        For k = 1 To 40
          If a(i, k - 1, j) > max Then max = a(i, k - 1, j)
          If a(i, k - 1, j) < min Then min = a(i, k - 1, j)
        Next
        DataGridView1(j, i * 47 + 44).Value = max
        DataGridView1(j, i * 47 + 45).Value = min
      Next
    Next

と比較すれば
わかりやすさは断然違います。
では、
   Sub g90(ByVal p As Integer)
     For i = 1 To 6
       DataGridView1(i, p * 47 + 44).Value = g91(p, i)
       DataGridView1(i, p * 47 + 45).Value = g92(p, i)
     Next
   End Sub
の役割は何でしょうか。iの0,1,2,3,4,5,7はそれぞれ国語、社会、数学、理科、合計、平均に対応しています。
つまり、ここの1次元ループの役割は各教科などの処理です。
そして、
   Function g91(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim max As Integer
     max = 0
     For i = 1 To 40
       If a(p, i - 1, q) > max Then max = a(p, i - 1, q)
     Next
     Return max
   End Function
が最高点の算出
   Function g92(ByVal p As Integer, ByVal q As Integer) As Integer
     Dim min As Integer
     min = 0
     For i = 1 To 40
       If a(p, i - 1, q) < min Then min = a(p, i - 1, q)
     Next
     Return min
   End Function
が最低点の算出を分担していたことがわかります。iの1から40は出席番号に相当します。

では、第8講の最後の課題を出してこの話を閉めます。

実行画面をご覧になればおわかりのように、成績一覧表作成ソフトは各学期の処理は行っていますが、
年間処理を行っていません。
そこで年間処理を行っていだますが、Private Sub Button1_Clickは、
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

      '見出し表示やデータ作成などの基本処理
     g()

     '各学期処理
     s()


     '年間処理
     t()

   End Sub
3つのプロシージャを組み立てものとして
gにはf1()からf4()までの基本処理を、sには各学期処理(すなわちf5()からf12()までの処理)を、tには年間処理をさせてください。


もちろん、年間処理の中には、各学期のデータを加えてデータを書き込むだけでなく、
各学期合計値・平均値の算出・表示、各学期各生徒の最高点・最低点の算出・表示など各学期で処理した同内容の各処理を行わなければなりません。
個々の処理は、SubプロシージャまたはFunctionプロシージャに担当させてください。

尚、tとsの内容は新たに作るのではなく、既存の部品(プロシージャ)を利用されてください。
tについても、出来るだけ既存の部品(プロシージャ)を再利用されてください。
既存の部品を再利用できる、これが構造化プログラミングの大きな利点の1つです。

部品の再利用といえば、実はf12()は、f10()を少し改造しておけば再利用できるので、不要なのです。
これについても考えてください。


第3話へ 第5話へ

006

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

数学研究室に戻る