1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【ExcelVBA】配列/動的配列の要素数を安全に求める

Last updated at Posted at 2019-04-23

はじめに

Excelでマクロを書いていると、稀に配列の要素数(長さ)を求めたい時があります。
Javaであれば {配列}.length で簡単に求められますが、VBAの場合はそこまで簡単ではありません。

UboundとLbound

VBAにはUboundとLboundという関数がありますが、これらの関数は以下のように「添え字の最大値/最小値を求める」という処理になっています。
配列の要素数に近いものではありますが、残念ながら配列の要素数そのものではありません...

関数名 処理内容
Ubound(配列) 配列の添え字の最大値を返す。
Lbound(配列) 配列の添え字の最小値を返す。

自作関数で配列の要素数を求める

以下のコードの「CalcArrayLength」という自作の関数が、配列の要素数を求める処理になります。

工夫した点は「引数をVariant型にすることで、配列がInteger型でもString型でも関係なく処理できる」という部分です。
引数をVariant型にすると、配列以外が引数となる恐れがあるため、IsArray関数で配列であるかどうかをチェックしています。

また、引数が「Redimで初期化されていない動的配列」の時は、On Error GoToを活用してエラーを吸収するようにしました。
「動的配列が初期化済みかどうかはSgn関数を使って調べる」と書かれているサイトも多いですが、@satoko138 さんのこちらの記事によると「Sgn関数を使って判定するのは不適切」ということなので、それを踏まえた実装にしてみました。

Module1
Option Explicit

Sub Test()
    ' 要素数が11の配列(※添え字が0~10)
    Dim ary1(10) As Integer
    MsgBox "ary1の長さ:" & CalcArrayLength(ary1)

    ' 要素数が10の配列(※添え字が1~10)
    Dim ary2(1 To 10) As String
    MsgBox "ary2の長さ:" & CalcArrayLength(ary2)
    
    ' 初期化済みの動的配列(※添え字が0~5)
    Dim ary3() As String
    ReDim ary3(5)
    MsgBox "ary3の長さ:" & CalcArrayLength(ary3)
    
    ' 引数が初期化されていない動的配列→-1が返される
    Dim ary4() As String
    MsgBox "ary4の長さ:" & CalcArrayLength(ary4)

    ' 引数が配列以外→-100が返される。
    MsgBox "配列以外:" & CalcArrayLength("abc")
End Sub


' 配列の要素数を求める。
'
' ary:対象となる配列。
' return:配列の要素数。引数として初期化されていない配列を指定した時は-1、配列以外を指定した時は-100を返す。
Function CalcArrayLength(ary As Variant) As Integer
    If (IsArray(ary)) Then
        If (IsInitialized(ary)) Then
            CalcArrayLength = UBound(ary) - LBound(ary) + 1
        Else
            CalcArrayLength = -1
        End If
    Else
        CalcArrayLength = -100
    End If

End Function

' 配列が初期化されているかをチェックする。
'
' ary:対象となる配列。
' return:配列が初期化済みならTrue、そうでなければFalseを返す。
Function IsInitialized(ary As Variant) As Boolean
    On Error GoTo NOT_INITIALIZED_ERROR
    Dim length As Long: length = UBound(ary)    ' 動的配列が初期化されていなければ、ここでエラーが発生する。
    IsInitialized = True
    Exit Function
   
' 配列が初期化されていない場合はここに飛ばされる。
NOT_INITIALIZED_ERROR:
    IsInitialized = False
End Function
1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?