前のページ|次のページ

プログラミングの応用1


配列

データを大量に扱う場合,一つ一つのデータにそれぞれ変数を宣言するのは非常に大変です.このため,同じ種類のデータであれば全体を代表す名前と個々を区別する番号を用いた変数を宣言することができます.このタイプの変数を「配列」変数といいます.配列を使用すれば,同種類のデータを大量に扱うプログラムをより単純に記述できます.

配列を代表する名前を「配列名」,個々を区別する番号を「インデックス」,一つ一つの変数を「配列要素」と呼びます.

1次元配列

配列変数の型宣言は次のように記述します.

Dim 配列名(インデックスの範囲) As データ型
        

宣言例

配列変数名を a ,インデックス最大値を 5 とした整数型の配列変数の宣言は次のようになります.

Dim a(5) As Integer
            

この宣言によって,a(0) から a(5) の「6つの変数」が用意されます.最初のインデックスは0から始まることに注意しましょう.

また,インデックスの最小値を指定して宣言することも可能です.

Dim a(1 To 5) As Integer
            

このように宣言した場合は,a(1) から a(5) の「5つの変数」が用意されます.

使用法

配列変数にデータを代入する場合はFor文を使用すると便利です.例えば,データが C1 から C10 セルに入力されている場合に,それらを配列変数に代入するには以下のように書きます.

Dim a(1 To 10) As Integer
Dim i As Integer

For i = 1 To 10

  a(i) = Cells(i,3).Value

Next i
        

次のようなデータについて,平均点を求めるプログラムを作成する.この時,各学生の得点は同種のデータなので配列変数を使用する.

学生番号 得点
77
83
56
68
35
96
84
72
63
10 51
11 45
12 74
合計
平均
Sub heikin()

  '変数宣言
  Dim tokuten(1 To 12) As Integer '得点の配列変数
  Dim ave As Double '平均点
  Dim gokei As Integer  '合計点
  Dim i As Integer  '学生番号

  '得点入力
  For i = 1 To 12
    tokuten(i) = Cells(i+1,2).Value
  Next i

  合計点初期値
  gokei = 0

  '合計点計算
  For i = 1 To 12
    gokei = gokei + tokuten(i)
  Next i

  '平均点計算
  ave = gokei/12

  '結果表示
  Cells(14,2).Value = gokei
  Cells(15,2).Value = ave

End Sub
              

2次元配列

インデックスを2つ使用した配列変数を使うこともできます.イメージとしては,Excelのセルのように行番号と列番号で指定できる2次元的な変数の集合と思ってください.

2次元の配列の型宣言は,次のように記述します.

Dim 配列名(インデックス1の範囲 , インデックス2の範囲) As データ型
        

宣言例

配列名を a ,第1インデックスの最大値を3,第2インデックスの最大値を4とした整数型の配列の宣言は,

Dim a(3,4) As Integer
        

この宣言で a(0,0) から a(3,4) まで \((3+1)\times(4+1) = 20\)個の変数が用意されます.

また,インデックスの最小値を指定することもできます.

Dim a(1 To 3, 2 To 5) As Integer
        

この宣言で,a(1,2) から a(3,4) まで \(3 \times 3 = 9\)個の変数が用意されます.

使用法

2次元配列変数にデータを代入する場合はFor文を2重に使用します.例えば,データが A1 から C10 セルに入力されている場合に,それらを配列変数に代入するには以下のように書きます.

Dim a(1 To 3, 1 To 10) As Integer
Dim i As Integer, j As Integer

For i = 1 To 3
  
  For j = 1 To 10

    a(i,j) = Cells(i,j).Value
    
  Next j

Next i
        

名前 国語 数学 英語 理科 社会 個人平均
A 71 95 76 89 72
B 61 86 74 60 80
C 76 81 80 76 73
D 63 51 71 60 79
E 66 75 88 55 65
F 78 54 63 84 51
G 88 78 69 69 93
H 76 68 55 60 78
I 78 61 79 51 88
J 79 63 82 75 83
K 82 87 78 72 55
L 49 71 77 87 61
M 68 81 68 93 75
N 83 87 60 81 62
O 56 88 58 72 72
P 86 72 68 98 62
Q 73 55 75 70 75
R 74 77 87 70 85
S 68 68 91 50 79
T 81 92 80 76 73
U 91 87 93 65 71
V 68 74 88 77 78
W 80 70 76 73 85
X 92 73 78 73 97
Y 69 67 79 85 83
Z 71 69 77 77 77
科目平均
Sub heikin2()

  '変数宣言
  Dim tokuten(1 To 26, 1 To 5) As Integer '得点の配列変数
  Dim id_ave(1 To 26) As Double, sbj_ave(1 To 5) As Double '平均点
  Dim id_gokei(1 To 26) As Integer, sbj_gokei(1 To 5) As Integer  '合計点
  Dim i As Integer, j As Integer

  '得点入力
  For i = 1 To 26
    For j = 1 To 5
      tokuten(i,j) = Cells(i+1,j+1).Value
    Next j
  Next i

  '合計点初期値
  For i = 1 To 26 
    id_gokei(i) = 0
  Next i

  For i = 1 To 5
    sbj_gokei(i) = 0
  Next i

  '合計点計算
  For i = 1 To 26
    For j = 1 To 5
      id_gokei(i) = id_gokei(i) + tokuten(i,j)
    Next j
  Next i

  For j = 1 To 5
    For i = 1 To 26
      sbj_gokei(j) = sbj_gokei(j) + tokuten(i,j)
    Next i
  Next j

  '平均点計算
  For i = 1 To 26
    id_ave(i) = id_gokei(i)/5
  Next i

  For i = 1 To 5
    sbj_ave(i) = sbj_gokei(i)/26
  Next i

  '結果表示
  For i = 1 To 26
    Cells(i+1,7).Value = id_ave(i)
  Next i

  For i = 1 To 5
    Cells(28,i+1).Value = sbj_ave(i)
  Next i

End Sub
              

プロシージャ

最初に説明したように,VBAでは単純な処理を行う単一の命令をステートメントといい,それらを組み合わせてある特定の作業させるようにしたものをプロシージャと呼びます.

サブプロシージャ

一般的に,VBAにおいて何らかの作業を行うプロシージャをサブプロシージャといいます.しかし複雑な作業の場合に,作業内容を一つのプロシージャにまとめて記述すると,処理の流れや構造が分かりにくくなりエラーも生じ易くなります.したがって,複雑な作業を実行する場合は,作業の全体を幾つかの より単純な作業の組み合わせになるように書き表した「メインプロシージャ」とし,分割した個々の作業内容(「サブルーチン」という)を別のプロシージャ「サブプロシージャ」として記述しておき,メインのプロシージャではそれらを呼び出して使用するように記述する,このように記述すれば,作業全体の流れが分かり易くなり,間違いも起こりにくくなります.また,たとえエラーが発生した場合でも,どこで発生したのかを解析しやすくなるため,修正しやすくなります.

構造1

サブプロシージャを呼び出すときは次のように記述します.

呼び出し側:

Call サブプロシージャ名
          

サブルーチン側:

Sub サブプロシージャ名
          

構造2

サブプロシージャは「引数」を取ることができ,この引数を使用してメインプロシージャとの間で値をやり取することが可能になります.この場合の記述の仕方は次のようになります.

呼び出し側:こちらの引数を実引数と呼ぶ.

Call サブプロシージャ名(実引数1, 実引数2, …)
          

サブルーチン側:こちらの引数を仮引数と呼ぶ.引数名は実引数と異なってもよい.

Sub サブプロシージャ名(仮引数1 As データ型, 仮引数2 As データ型, …)
          

配列を引数とする場合は,仮引数の記述を次のようにする.

Sub サブプロシージャ名(仮引数1() As データ型, 仮引数2() As データ型, …)
          

身長と体重のからBMIを計算し結果を表示するプログラムを作ってみる.

身長cm 体重kg BMI 結果
(身長入力) (体重入力)
Sub taikei()

  Dim shincho As Single, taiju As Single
  Dim bmi As Single

  shincho = Cells(2,1).Value
  taiju = Cells(2,2).Value

  Call bmi_keisan(shincho,taiju,bmi)

  Cells(2,3).Value = bmi

  If bmi < 18.5 Then
    Call yase
  ElseIf bmi < 25 Then
    Call futsu
  Else 
    Call futo
  End If

End Sub

Sub bmi_keisan(h As Single, w As Single, b As Single)
  b = w/(h/100)^2
End Sub 

Sub yase()
  Cells(2,4).Value = "低体重"
End Sub

Sub futsu()
  Cells(2,4).Value = "標準"
End Sub

Sub futo()
  Cells(2,4).Value = "肥満"
End Sub

練習問題5-1

Excelのブックに新しいシートを追加し,VBEで新しい標準モジュールを挿入します.プロジェクトエクスプローラーに Sheet4 と Module4 が表示されるはずです.

Module4 のコードウィンドウに新しい Sub プロシージャを作成します.

以下のプログラムのどれかを作成しましょう.

練習問題 5-1a

次のデータを使用して「平均値,分散,標準偏差」を求めるプログラムを作ってみましょう. この時,メインプロシージャから「学生数,得点データ」を受け取り,「平均値,分散,標準偏差」を計算する1つのサブプロシージャを作成し,メインプロシージャではそれを呼び出すように作成してください.偏差,分散,標準偏差に関しては「解説」を参照.

結果は得点データを入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet4にフォームコントロールのボタンを挿入し,プログラムを登録して名前を「ex_051a」に変えて下さい,ボタンはシートの左上あたりに配置してください.

名前 得点
A 71
B 61
C 76
D 63
E 66
F 78
G 88
H 76
I 78
J 79
K 82
L 49
M 68
N 83
O 56
P 86
Q 73
R 74
S 68
T 81
U 91
V 68
W 80
X 92
Y 69
Z 71
平均
分散
標準偏差

練習問題 5-1b

次の2次元配列のデータを使用して科目毎の標準偏差を求めるプログラムを作ってみましょう. この時,メインプロシージャから「学生数,科目,得点データ」を受け取り,各科目の「標準偏差」を計算するサブプロシージャを作成し,メインプロシージャではそれを呼び出すように作成してください.標準偏差に関しては「解説」を参照.

結果は得点データを入力したセルの下のセルに表示するようにし,使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにしてください.Sheet4にフォームコントロールのボタンを挿入し,プログラムを登録して名前を「ex_051b」に変えて下さい,ボタンはシートの左上あたりに配置してください.

名前 国語 数学 英語 理科 社会
A 71 95 76 89 72
B 61 86 74 60 80
C 76 81 80 76 73
D 63 51 71 60 79
E 66 75 88 55 65
F 78 54 63 84 51
G 88 78 69 69 93
H 76 68 55 60 78
I 78 61 79 51 88
J 79 63 82 75 83
K 82 87 78 72 55
L 49 71 77 87 61
M 68 81 68 93 75
N 83 87 60 81 62
O 56 88 58 72 72
P 86 72 68 98 62
Q 73 55 75 70 75
R 74 77 87 70 85
S 68 68 91 50 79
T 81 92 80 76 73
U 91 87 93 65 71
V 68 74 88 77 78
W 80 70 76 73 85
X 92 73 78 73 97
Y 69 67 79 85 83
Z 71 69 77 77 77
標準偏差

解説

データの様々な性質を調べる手法を「統計」という.具体的には様々な統計量を計算することによって成される.

最も基本的な統計量は「平均」であり,データ:\(x_i\quad i = 1, \cdots , n\)に対して次のように定義される. \[ \bar{x} = \frac{x_1 + x_2 + \cdots + x_n}{n} = \frac{1}{n}\sum_{i=1}^{n}x_i \] 各データの平均からのずれを「偏差」,偏差の2乗の平均が「分散:\(\sigma^2\)」と呼ばれ,データ全体が平均からどのくらいの広がりを持っているのかを表す. \[ \sigma^2 = \frac{(x_1-\bar{x})^2 + (x_2 - \bar{x})^2 + \cdots + (x_n - \bar{x})^2}{n} = \frac{1}{n}\sum_{i=1}^{n}(x_i - \bar{x}) ^2 \] 通常は分散の平方根を取った「標準偏差:\(\sigma\)」がデータの広がりを表す指標となる. \[ \sigma = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(x_i - \bar{x})^2} \]


ファンクションプロシージャ

ファンクションプロシージャもサブルーチンの一つだが,VBAに組み込まれた数学の関数のような形で機能する. 従って,ファンクションプロシージャは受け取ったデータを処理し,その結果をメインのプロシージャに返す様に記述する.

構造1

ファンクションプロシージャを呼び出すときは次のように記述する.

呼び出し側:こちらの引数を実引数と呼ぶ.結果を受け取る変数はファンクションプロシージャのデータ型と合わせる

変数名 = ファンクションプロシージャ名(実引数名)
          

サブルーチン側:こちらの引数を仮引数と呼ぶ.引数名は実引数と異なってもよい.返す結果のデータ型は指定しておく

Function  ファンクションプロシージャ名(仮引数名 As データ型) As データ型

  プロシージャ名 = 計算式(仮引数名を用いて記述)

End Function
          

ユーザー定義関数:1変数関数

Sub kansu1()

  Dim x As Double, y As Double

    x = Rane("A1").Value

    y = func1(x)

    Range("B1").Value = y

End Sub

Function func1(z As Double) As Double

  func1 = z*Exp(-z^2)*Sin(3*z + 1)

End Function
        

構造2

複数の引数を持つファンクションプロシージャを定義することもできる.

呼び出し側:

変数名 = プロシージャ名(実引数1, 実引数2, …)
        

サブルーチン側:

Function プロシージャ名(仮引数1 As データ型, 仮引数2 As データ型, …) As データ型

  プロシージャ名 = 計算式(仮引数で記述)

End Function
        

ユーザー定義関数:2変数関数

Sub kansu2() 

  Dim x As Double, y As Double, z As Double

    x = Range("A1").Value
    y = Range("B1").Value

    z = func2(x,y)

    Range("C1").Value = z 

End Sub

Function func2(x1 As Double, x2 As Double) As Double

  func2 = ( (x1^2+x2^2)^2-6*(x1^2+x2^2)-3 )*Exp(-(x1^2+x2^2-1)/2)

End Function
          


練習問題5-2

「ex_051x」のサブプロシージャの下に新しい Sub プロシージャ「ex_052a または ex052b または ex052c」を作成します.

次のどれかの場合のプログラムを作成しましょう.

  1. ex052a:「植物」だけの個体数の変動を計算するプログラムを作る.個体数の変化を表す計算式をファンクションプロシージャとして記述する.
  2. ex052b:「植物,草食動物」の個体数の変動を計算するプログラムを作る.個体数の変化を表す計算式をファンクションプロシージャとして記述する.
  3. ex052c:「植物,草食動物,肉食動物」の個体数の変動を計算するプログラムを作る.個体数の変化を表す計算式をファンクションプロシージャとして記述する.

入出力は,セルに各生物種間の係数(解説参照)と最初の個体数,世代数,結果(指定した世代での個体数)の表で行う.表の構成は,作成するプログラムに応じて変えてください.

使用するセルはこのプログラムを登録するボタンの下に来る位置のセルにする.Sheet4にフォームコントロールのボタンを挿入し,プログラムを登録して名前を ex_052a または ex052b または ex052c に変える,ボタンはex_11の横に適当な間隔を開けて配置する.

生物間の係数
\(A_{ij}\)自然増殖植物草食肉食
植物数値(> 0)数値 (< 0)数値 (< 0)0
草食0数値 (> 0)数値 (< 0)数値 (< 0)
肉食00数値 (> 0)数値 (< 0)
個体数
世代数0(世代数を入力)
植物(初期数値を入力)
草食(初期数値を入力)
肉食(初期数値を入力)

解説

植物は一定の割合で増殖し,その個体数と草食動物の数に比例した割合で減少する. 草食動物は,植物の数に比例した割合で増殖し,その個体数と肉食動物の数の両者に比例した割合で減少する. 肉食動物は,草食動物の数に比例した割合で増殖し,その個体数に比例した割合で減少する.

個体数の世代間変化は, \(x_n, y_n, z_n\)を\(n\)世代目の植物,草食動物,肉食動物の個体数とし,\(A_{ij}\)を各関係を表す係数として考えると以下のように表される.全てをかなり小さい値にしないとすぐ絶滅します.

\(A_{ij}\) x y z
x 植物による変化率(生存競争):\(A_{xx}\) < 0 草食による変化率(食われる):\(A_{xy}\) < 0 肉食による変化率(食われない):\(A_{xz}\) = 0
y 植物による変化率(食べる):\(A_{yx}\) > 0 草食による変化率(生存競争):\(A_{yy}\) < 0 肉食による変化率(食われる):\(A_{yz}\) < 0
z 植物による変化率(食べない):\(A_{zx}\) = 0 草食による変化率(食べる):\(A_{zy}\) > 0 肉食による変化率(生存競争):\(A_{zz}\) < 0

自然増殖:\(A_{x}\) > 0,\(A_y = 0\) ,\(A_z = 0\):勝手に増えるのは植物だけ.

次の世代における個体数は次のような式で決まる(係数が0の場合も書いてある).ただし,個体数が負になった場合は0にする. \begin{align} x_{n+1} &= x_n + A_{x}x_n + A_{xx}x_n^2 + A_{xy}x_ny_n + A_{xz}x_nz_n\\ y_{n+1} &= y_n + A_{y}y_n + A_{yx}y_nx_n + A_{yy}y_n^2 + A_{yz}y_nz_n\\ z_{n+1} &= z_n + A_{z}z_n + A_{zx}z_nx_n + A_{zy}z_ny_n + A_{zz}z_n^2\\ \end{align} ヒント:Int(number) とすると数値 number の整数部分を取り出せる.