| Home | Menu | GesutBook |

配列変数

 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.gif(2137 byte)
【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.gif(8440 byte)
【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.gif(6012 byte)
【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.gif(5954 byte)
【Image30226】
 次に、ReDimステートメントなんですが 多次元配列の場合、このステートメントを使って
変更できる要素数は、配列の1番最後の要素数だけです。つまり、2次元配列の場合は「2」番
目の要素数だけ変更でき「1」番目の要素数は変更できません。3次元配列の場合は「3」番目
の要素数だけ変更でき「1」番目と「2」番目は、変更できません。
image30227.gif(3128 byte)
【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.gif(3057 byte)
【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.gif(3485 byte)
【Image30229】
 ここでのポイントは、Variant型変数に セル範囲(値)を代入すると 2次元配列になると言
うことです。わざわざループしなくても良いのです。--- 【List30215】(1)でセル範囲を
配列に取込 なにかしらの処理をした後に【List30214】(2)のステートメントで再びセルに
転記する。 --- この組み合わせって結構、合理的と思いませんか?





| Home | Menu | Back | Next |