配列の要素数を動的に変えるVBA | システムエンジニアライフ

配列の要素数を動的に変えるVBA

ヘッダー広告
スポンサードリンク

プログラミングでは配列は必須の技術です。
通常の変数には一つの値しか入力することが出来ませんが、配列を使用することで同じ名前の配列に様々な値を入力することが可能となります。

これは繰り返しで何回も同じ処理を行う時に強く、また開発が終わり後々修正するとなった場合にもロジックがわかりやすい(保守性が高い)という利点があります。

通常の配列は、最初に一つの変数に対して何件までデータを格納できるかを設定します。
しかし、データを格納する件数が状況によって変動して、何件データを格納できるように設定するのかが判断できない場合があります。
この時に、プログラム初心者の場合だと適当に大きな件数を入れられるように設定しようと考えると思うのですが、使わない余計なデータ件数を準備しておくことで、CPUを余計に使ってしまって動作が遅くなってしまったり、予期しないエラーが発生する可能性があります。

そこで格納するデータの件数がわからない時に使われるのが、動的配列になります。

本来の配列では最初に格納するデータ件数を設定しますが、動的配列の場合には処理の途中でデータの件数を設定したり変更したりすることが可能となります。
これによってデータ件数がわからなかったり、データ件数の変動が大きい場合にも状況に応じたデータの件数を設定することが可能となります。

変数に格納出来るデータの件数のことを、配列の要素数と言います。

今回はこの配列の要素数を動的に変えるVBAをご紹介したいと思います。

※ちなみに私が考えるEXCEL VBAでの配列の良い点は、処理速度が圧倒的に速いことです。
 例えばEXCELの関数式を使う等、EXCELのシート内で処理を実行すると処理にかなりの時間がかかってしまいますが、配列に格納したまま計算等を行うと、格段に処理速度が改善されます。
 処理速度の改善に関する記事は、また別途記載します。

動的配列

通常の配列

まず通常の配列処理を記載します。
以下のサンプルをご覧ください。

Public Sub ArraySet1()

    Dim Fruits(2) As String
    Dim i As Long
    
    Fruits(0) = "orange"
    Fruits(1) = "cherry"
    Fruits(2) = "papaya"
    
    For i = 0 To UBound(Fruits)
        
        Debug.Print Fruits(i)
    
    Next
    
End Sub

通常の配列処理を行う場合には、最初に変数名を宣言する際に配列の要素数を定義します。
今回の場合は要素(2)までを使用可能とするように設定しています。

Dim Fruits(2) As String

そして、変数に値を設定したり使う方法は、普段の変数を扱うのとほぼ変わりはありません。
配列の場合には、変数名の後ろに(要素番号)を付けてあげれば他の変数と同じように操作が可能となります。

・値を設定する場合
Fruits(0) = “orange”

・値を使用する場合
Debug.Print Fruits(0)

こちらが通常の配列の使い方になりますが、最初に説明したように最初に設定した要素数を超える要素数を設定するとエラーが返却されます。

Public Sub ArraySet1()

    Dim Fruits(2) As String
    Dim i As Long
    
    Fruits(0) = "orange"
    Fruits(1) = "cherry"
    Fruits(2) = "papaya"
    
    '要素番号3は設定されていないため、エラーとなる。
    Fruits(3) = "banana"
    
    For i = 0 To UBound(Fruits)
        
        Debug.Print Fruits(i)
    
    Next
    
End Sub

このように変数名Fruitsには、最初に0~2の要素番号を設定できるように宣言したにも関わらず、宣言していない要素番号(3)に対して値を設定しようとすると、以下のように『実行時エラー’9′:インデックスが有効範囲にありません。』のエラーが出力されてしまいます。


このように通常の配列だと、最初に設定した要素数以上の要素を使おうとするとエラーとなってしまいますので、最初から要素数を大きく設定しておくか、これからご紹介する動的配列を使用するのかが対応する方法となります。

動的配列

では配列の要素数を動的に変えるVBAを記載します。
以下のサンプルをご覧ください。

Public Sub ArraySet2()

    Dim Fruits() As String
    Dim i As Long
    
    ReDim Fruits(2)
    
    Fruits(0) = "orange"
    Fruits(1) = "cherry"
    Fruits(2) = "papaya"
    
    ReDim Preserve Fruits(5)
    
    Fruits(3) = "banana"
    Fruits(4) = "lemon"
    Fruits(5) = "peach"
    
    For i = 0 To UBound(Fruits)
        
        Debug.Print Fruits(i)
    
    Next

End Sub

通常の配列処理を行う場合には、最初に変数名を宣言する際に配列の要素数を定義していましたが、動的配列の場合は変数名を宣言する際には要素数は指定しないまま変数宣言を行います。

Dim Fruits() As String

そして変数をしたいときに『Redim』というものを使用して要素数を設定することが必要となります。

以下のサンプルのようにすることによって、Redim後から配列の要素数が設定され、配列が使用可能となります。

ReDim Fruits(2)

そしてもし途中で再度配列の要素数を変更したい場合には、再度『Redim』を使用します。
ここでの注意点は、要素数を変更する対象の配列に設定されている値を、そのまま引き継ぎたいという場合には、『ReDim Preserve』という記述にて配列要素数の設定をしてあげる必要があります。
もし『Preserve』を記載しないと、それまでに設定した要素番号に対する値は全て削除されてしまいますので、ご注意ください。

ReDim Preserve Fruits(5)

先ほどご紹介したプログラムの実行結果はこちらになります。

orange
cherry
papaya
banana
lemon
peach

これがVBAでの動的配列を扱うコードとなります。
これを実際に使うようなコードの場合の処理を次に紹介したいと思います。

動的配列の応用

次にご紹介するコードは、Sheet1に存在する果物の一覧を配列に格納して出力するというコードになります。
この時、果物一覧に入るデータ数は変動すると仮定して、データ数がかなり多くなっても耐えられるようにコーディングしています。

果物一覧データ


Public Sub ArraySet3()

    Dim Fruits() As String
    Dim i As Long
    Dim j As Long
    
    Const DEFAULT_COUNT As Long = 3
    Const START_ROW As Long = 2
    
    ReDim Fruits(DEFAULT_COUNT - 1)
    
    
    i = 0
    
    'データセット
    With ThisWorkbook.Worksheets("Sheet1")
    
        Do Until .Cells(START_ROW + i, 1) = ""
            
            If i Mod DEFAULT_COUNT = 0 Then
                ReDim Preserve Fruits(i + DEFAULT_COUNT - 1)
            End If
            
            Fruits(i) = .Cells(START_ROW + i, 1)
            
            i = i + 1
    
        Loop
        
        ReDim Preserve Fruits(i - 1)
    
    End With
    
    'データ出力
    For j = 0 To UBound(Fruits)
        
        Debug.Print Fruits(j)
    
    Next
    
End Sub

このロジックのポイントは、以下の点になります。

1.配列の要素数を増加させる数を定数で事前に設定する
動的配列を使う時には、途中で配列の要素数を変更していく必要があるのですが、一件増えるごとに配列の要素数を増加させていくと、無駄に処理時間がかかってしまうため、以下のように一定の要素数が増加したら要素数を増やすというようにロジックを書くことで、処理速度が向上します。
この時設定する定数の値は、データがどの程度の件数になりえるのかを把握したうえで、適切な件数を設定すると良いでしょう。

Dim Fruits() As String
Const DEFAULT_COUNT As Long = 3
ReDim Fruits(DEFAULT_COUNT – 1)

If i Mod DEFAULT_COUNT = 0 Then
    ReDim Preserve Fruits(i + DEFAULT_COUNT – 1)
End If

2.配列への値セットが完了したら、使っていない要素は削除する
こちらは動的配列で拡張した要素のうち、使っていない要素を削除するというものになります。
使っていない要素が存在するとバグや処理速度劣化の原因になったりするため、セット処理が完了したら使っていない要素を削除する方が良いでしょう。

削除前の配列状態

Fruits(0):オレンジ
Fruits(1):さくらんぼ
Fruits(2):パパイヤ
Fruits(3):バナナ
Fruits(4):レモン
Fruits(5):(データなし)

このように配列への値セット処理が完了した直後には、Fruits(5)には値が入っていないにも関わらず配列が用意されている状態です。
これをRedimすることによって無駄な要素を削除することで、Fruits(0)~Fruits(4)までしか配列は存在しないように変更することが重要となります。

配列の要素を(1)から始める方法

最後におまけのとして、通常であれば配列の要素は(0)から始まるものですが、これを(1)から始めるように設定することが可能です。
プログラム初心者には、(0)から始まるのがややこしくてわかりにくいという方もいらっしゃると思いますので、ここでご紹介させていただきます。

※ただし(0)から始める方が一般的ですし、中級者以上からは(1)から始まる方がわかりにくいので、慣れてきたらこの設定はしない方が良いと思います。

設定方法はモジュールの一番上のプロシージャの前に以下のコードを記述するだけです。

Option Base 1

実際の使い方は以下の通りとなります。

Option Explicit
Option Base 1

Public Sub ArraySet1()

    Dim Fruits(2) As String
    Dim i As Long
    
    Fruits(1) = "orange"
    Fruits(2) = "cherry"
    
    For i = 1 To UBound(Fruits)
        
        Debug.Print Fruits(i)
    
    Next
    
End Sub

こちらではFruitsの配列は(1)から始まっています。
もし上記のコードでFruits(0)を設定すると、『インデックスが有効範囲にありません。』が出力されてエラーとなります。

本日はここまで!

フッター広告

スポンサードリンク



シェアする

  • このエントリーをはてなブックマークに追加

フォローする