配列変数
3 多次元配列
今まで見てきた配列は、要素数が1つのものでしたが、複数の要素数を持つ配列も、VBAでは
扱うことが出来ます。これを多次元配列と言います。
たとえば「Dim myInt(2,3) As Integer」という具合に添え字をカンマで区切って 2つ記述
した場合、
myInt(1,1)
myInt(1,2)
myInt(1,3)
myInt(2,1)
myInt(2,2)
myInt(2,3)
|
合計「6」個のInteger型変数、を宣言したことになります。ここでピンッときた人は鋭い!
2次元配列は、Cellsプロパティーとそっくりですね。実際のCodingでも、この2つが組み合
わされて使われる事がたくさんあります。
さっそくSampleを書いてみますね。【Image30223】は、A列に顧客Code、B列にその売上が書
かれているリストです。これをもとに、各顧客Codeごとの売上個数の合計を求めます。
【Image30223】
|
【List30211】
|
Sub Ver2_Sa9()
Dim myCal() As Long
Dim r As Long
Dim i As Long
Dim myInd As Long
i = 3
ReDim myCal(1 To 2, 1 To 1) '...............................................(1)
myCal(1, 1) = Cells(2, 1).Value
Do Until Cells(i, 1).Value = ""
myInd = UBound(myCal, 2) '...............................................(2)
For r = LBound(myCal, 2) To UBound(myCal, 2) '...........................(3)
If myCal(1, r) = Cells(i, 1).Value Then Exit For
Next r
If r = UBound(myCal, 2) + 1 Then
ReDim Preserve myCal(1 To 2, 1 To myInd + 1) '.......................(4)
myCal(1, myInd + 1) = Cells(i, 1).Value
End If
i = i + 1
Loop
For i = LBound(myCal, 2) To UBound(myCal, 2) '.............................(5)
myCal(2, i) = Application.WorksheetFunction.SumIf(Columns(1), myCal(1, i), Columns(2))
Cells(i, 4).Value = myCal(1, i)
Cells(i, 5).Value = myCal(2, i)
Next i
Erase myCal
End Sub
|
| (1) |
動的配列に要素を定義します。 |
| (2) |
UBound関数は、指定された配列の要素数の上限値を返します。 |
| (3) |
LBound関数は、UBound関数の反対で 指定された配列の要素数の下限値を返します。 |
| (4) |
セルの値を、すべての要素と比較して あればループを抜け、無ければ要素を1つ
増やして新しい顧客Codeを代入します。ここがポイントです。 |
| (5) |
(3)で求められた検索条件をつかって、合計を求めながら D列とE列に転記してい
きます。 |
【Image30224】
少しややこしいCodeですけど、2次元配列とCellsプロパティーの相性が良いことが、解って
いただけたでしょうか?
LBound関数,UBound関数とReDimステートメントについて補足しておきますね。
「UBound(myCal, 2)」は、配列変数「myCal」の「2」つ目の要素数の上限値を求めています。
カンマで区切られた後の「2」が、何番目の要素数の上限値かを示しています。1次元の配列の
場合は、「UBound(myCal, 1)」または、単に「UBound(myCal)」と記述します。なお前節で取
り上げた、Option Baseステートメントによっては、この関数の返す数値が異なりますので注
意して下さい。
【Ris30212】は、「Option Base 0」なので 「myInt1」は、全部で11個の要素を持ってい
ます。
|
【List30212】
|
Option Explicit
Option Base 0
Sub Ve2r_Sa10()
Dim myInt1(10) As Integer
Dim myInt2(1 To 10) As Integer
Debug.Print "myInt1の下限値"; LBound(myInt1); "上限値"; UBound(myInt1)
Debug.Print "myInt2の下限値"; LBound(myInt2); "上限値"; UBound(myInt2)
End Sub
|
【Image30225】
【Ris30213】は、「Option Base 1」なので 「myInt1」は全部で10個の要素を持っていま
す。「myInt2」は、どちらの場合もいっしょで10個の要素を持っていますね。どちらの書き
方をするかは、好みの問題ですが、後者のほうがプログラムの精度が上と言えそうですね。
|
【List30213】
|
Option Explicit
Option Base 1
Sub Ver2_Sa11()
Dim myInt1(10) As Integer
Dim myInt2(1 To 10) As Integer
Debug.Print "myInt1の下限値"; LBound(myInt1); "上限値"; UBound(myInt1)
Debug.Print "myInt2の下限値"; LBound(myInt2); "上限値"; UBound(myInt2)
End Sub
|
【Image30226】
次に、ReDimステートメントなんですが 多次元配列の場合、このステートメントを使って
変更できる要素数は、配列の1番最後の要素数だけです。つまり、2次元配列の場合は「2」番
目の要素数だけ変更でき「1」番目の要素数は変更できません。3次元配列の場合は「3」番目
の要素数だけ変更でき「1」番目と「2」番目は、変更できません。
【Image30227】
【List30314】のCodeは、【Ris30211】と全く同じ結果を返します。どうしても多次元配列
の最初の要素数を変更したい場合は、(1)のように配列の入れ替えなどを行って下さいモジュ
ール関数には、。ワークシート関数TRANSPOSEのように配列の行列を入れ替える関数等は用意
されていないので、いろいろと工夫してみて下さいね。
|
【List30214】
|
Sub Ver2_Sa12()
Dim myCal() As Long
Dim myCal2() As Long
Dim r As Long
Dim i As Long
Dim myInd As Long
i = 3
ReDim myCal(1 To 2, 1 To 1)
myCal(1, 1) = Cells(2, 1).Value
Do Until Cells(i, 1).Value = ""
myInd = UBound(myCal, 2)
For r = LBound(myCal, 2) To UBound(myCal, 2)
If myCal(1, r) = Cells(i, 1).Value Then Exit For
Next r
If r = UBound(myCal, 2) + 1 Then
ReDim Preserve myCal(1 To 2, 1 To myInd + 1)
myCal(1, myInd + 1) = Cells(i, 1).Value
End If
i = i + 1
Loop
For i = LBound(myCal, 2) To UBound(myCal, 2)
myCal(2, i) = Application.WorksheetFunction.SumIf(Columns(1), myCal(1, i), Columns(2))
Next i
ReDim myCal2(1 To UBound(myCal, 2), 1 To UBound(myCal, 1))
For i = LBound(myCal, 1) To UBound(myCal, 1) '..............................(1)
For r = LBound(myCal, 2) To UBound(myCal, 2)
myCal2(r, i) = myCal(i, r)
Next r
Next i
Range(Cells(1, 4), Cells(UBound(myCal2, 1), UBound(myCal2, 2) + 3)) = myCal2 '..(2)
Erase myCal, myCal2
End Sub
|
| (1) |
2つの配列変数を使って、値の入れ替え(行列の入れ替え)作業を行っています。 |
| (2) |
配列変数の値をいっぺんにセルへ転記しています。 |
(2)のステートメントは、2次元配列に限定された使い方ですが、ループすることなく配列の
中味をすべて しかも たった1行でセルへ転記しています。マニアックな使い方ですが、是
非 覚えておきましょう。
最後に、もう1つだけSampleを載せておきますね。
【List30215】は、文字列式のうち ひらがな部分だけを【Imag30228】のリストに従ってカ
タカナに変換するCodeです。
【Image30228】
|
【List30215】
|
Sub Ver2_Sa13()
Dim i As Integer
Dim r As Long
Dim myList As Variant
Dim myStr As String
Dim myStr2 As String
myStr = "今日は良い天気ですね"
myList = Worksheets(1).Range("A1").CurrentRegion.Value '.....................(1)
For i = 1 To Len(myStr)
For r = LBound(myList, 1) To UBound(myList, 1)
If Mid(myStr, i, 1) = myList(r, 1) Then
myStr2 = myStr2 & myList(r, 2)
Exit For
End If
Next r
If r = UBound(myList, 1) + 1 Then myStr2 = myStr2 & Mid(myStr, i, 1)
Next i
Debug.Print myStr2
Erase myList
End Sub
|
【List30215】の実行結果です
【Image30229】
ここでのポイントは、Variant型変数に セル範囲(値)を代入すると 2次元配列になると言
うことです。わざわざループしなくても良いのです。--- 【List30215】の(1)でセル範囲を
配列に取込 なにかしらの処理をした後に【List30214】の(2)のステートメントで再びセルに
転記する。 --- この組み合わせって結構、合理的と思いませんか?
|