VBA基礎1:変数・配列・辞書・オブジェクト
1.概要
VBA基礎として変数・配列を紹介します。Excel VBAに関して様々な本・ブログがあるため本記事では自分の備忘録用まとめ記事となっております。
2.基礎知識
2-1.プロシージャ
VBAで記載する処理をプロシージャと呼び、主に3種類あります。なお同じ変数名・プロシージャ名は使用できないため命名規則は各自注意が必要です。
2-2.モジュール作成
「Alt+F11」よりVBEを開いて標準モジュールを追加します。そのモジュール内にプロシージャを記載することでマクロを作成します。
3.変数
3-1.変数名の定義方法
Pythonでも同じですが変数を見やすくし何を表しているのか(変数、定数、関数、クラスなど)を明確にすることは重要です。参考までに命名規則の記事は下記の通りです。
3-2.変数の型式および宣言(Dim)
Pythonではデータ型を定義しませんが、Excelでは一般的に使用する変数は定義(宣言)します。定義方法は下記の通りです。もし変数後ろの"As <データ型>"を記載しない場合は自動でVariantとして定義されるため、記載しなくてもエラーにはなりません(VBAの省略可能な記述について)。
[IN]
Dim <変数名> As <データ型>
データ型一覧は下記の通りです(【VBA基本】変数のデータ型一覧参照)。
実際のところ変数は宣言しなくても使用可能ですがプロシージャの上に"Option Explicit"を記載すると宣言していない変数を使用できないようにする制限を追加できます。
[Sampleコード]
Option Explicit
Sub Test()
Dim A As String
A = "Hellow World"
Debug.Print A
End Sub
[OUT]
Hellow World
3-3.変数の適用範囲
VBAでは変数の宣言箇所・方法により適用範囲(使用できるエリア)が異なり、大きく分けて3つあります(詳細は下記記事参照)。
4.配列:List
配列とはPythonのList型のように複数の値を格納できる変数です。配列の作成方法および値の抽出方法を紹介します。
4-1.配列の作成1:配列の定義
記載方法はPythonとは異なり要素ごとに値を代入していきます。注意点としては下記の通りです。
[記法1:要素数のみ指定]
Dim <変数名>(配列の最大index)
<変数名>(要素番号) = 指定要素数の値
[記法2:要素数の最小値・最大値を指定]
Dim <変数名>(Min to Max)
<変数名>(要素番号) = 指定要素数の値
[記法3:動的配列]
Dim <変数名>()
Redim <変数名>(指定したい要素数)
サンプルコードは下記の通りです。
[IN]
Sub Test1()
Dim Weekdays(4)
Weekdays(0) = "Monday"
Weekdays(1) = "Tuesday"
Weekdays(2) = "Wednesday"
Weekdays(3) = "Thursday"
Weekdays(4) = "Friday"
Debug.Print Weekdays(1) 'Tuesdayが出力
End Sub
[OUT]
Tuesday
[IN]
Sub Test2()
Dim Weekdays(1 To 4) '配列の要素数を1から開始に変更
'要素数0は存在しないため定義するとエラーとなる
Weekdays(1) = "Tuesday"
Weekdays(2) = "Wednesday"
Weekdays(3) = "Thursday"
Weekdays(4) = "Friday"
Debug.Print Weekdays(0) '1開始にしているため要素数0だとエラーがでる
End Sub
[OUT]
実行時エラー'9':
インデックスが有効範囲にありません。
[IN]
Sub Test3()
Dim Weekdays() '動的配列
ReDim Weekdays(4) '配列の要素数を0~4に変更する
Weekdays(0) = "Monday"
Weekdays(1) = "Tuesday"
Weekdays(2) = "Wednesday"
Weekdays(3) = "Thursday"
Weekdays(4) = "Friday"
Debug.Print Weekdays(0)
End Sub
[OUT]
Monday
4-2.配列の作成2:Split関数を使用
VBA関数で出力される値が配列であることを利用します。ここではsplit関数を使用して文字列を分割することで配列を作成しました。
[IN]
Option Explicit
Sub Test()
Dim Weekdays_Str As String
Dim Weekdays(4) '動的配列: Dim Weekdays ()はエラー※Weekdays() As String ならOK
Weekdays_Str = "Monday, Tuesday, Wednesday, Thursday, Friday"
Weekdays = Split(Weekdays_Str, ",") '文字列を指定文字で分割
Debug.Print Weekdays(0), Weekdays(4)
End Sub
[OUT]
Monday Friday
4-3.配列数の確認:LBound/UBound関数
配列数の確認はLBound関数とUBound関数を使用することで確認できます。配列でindexの開始/終了値を決めた場合はその値が出力されます。
[IN]
Sub Test()
Dim Weekdays(4)
Weekdays(0) = "Monday"
Weekdays(1) = "Tuesday"
Weekdays(2) = "Wednesday"
Weekdays(3) = "Thursday"
Weekdays(4) = "Friday"
Debug.Print "LBound関数", LBound(Weekdays) '配列の最初のindex取得
Debug.Print "UBound関数", UBound(Weekdays) '配列の最後のindex取得
Debug.Print "配列数", UBound(Weekdays) - LBound(Weekdays) + 1 '配列数
End Sub
[OUT]
LBound関数 0
UBound関数 4
配列数 5
4-4.配列のデータ抽出
配列からデータ抽出する場合はindexを指定するか、L・UBound関数を使用してFor文でまとめて取得します。
[抽出方法1:個別に取得]
配列(index)
[抽出方法2:LBound/UBound関数を使用0]
For i = LBound(配列) To UBound(配列)
Debug.Print 配列(i) '全配列データをFOR文で出力
Next
[IN]
Sub Test()
Dim Weekdays(4)
Dim i As Long
Weekdays(0) = "Monday"
Weekdays(1) = "Tuesday"
Weekdays(2) = "Wednesday"
Weekdays(3) = "Thursday"
Weekdays(4) = "Friday"
Debug.Print "Indexで抽出", Weekdays(0) 'index番号を指定
For i = LBound(Weekdays) To UBound(Weekdays)
Debug.Print Weekdays(i) '全配列データをFOR文で出力
Next
End Sub
[OUT]
Indexで抽出 Monday
Monday
Tuesday
Wednesday
Thursday
Friday
5.辞書型:連想配列
Pythonでいう辞書型データを作成する場合はDictionaryを使用します。
5-1.環境構築:Microsoft Scripting Runtime
連想配列(Dictionary)を使用するには「ツール」->「参照設定」->「Microsoft Scripting Runtime」で選択しておきます。
※「Microsoft Scripting Runtime」をチェックせずCreateObjectで「Scripting.Dictionary」を生成しても連想配列は使用できます。ただし参照設定しておくと自動補完機能が働くため設定しておくことを推奨します。
なお、Dictionaryのメソッド・プロパティはそれぞれ下記の通りです。
5-2.辞書の作成1:Dictionaryの定義
辞書を作成するためのDictionaryの定義方法は下記の通りです。
[辞書の定義方法1:参照設定で「Microsoft Scripting Runtime」選択済み]
Dim dict As New Dictionary
dict.Add <KEY>, <VALUE> 'Dictionaryオブジェクトの初期化、要素の追加
dict(<KEY>> = VALUE 'こちらの方法でもよい
[辞書の定義方法2:環境構築をしていない]
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
dict.Add <KEY>, <VALUE> 'Dictionaryオブジェクトの初期化、要素の追加
サンプルコードは下記の通りです。
[IN]
Sub Test()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
dict.Add "BTC", 2992808
dict.Add "ETH", 209926
dict.Add "XRP", 47.845 '別パターンでデータ登録
End Sub
[OUT]
3
5-3.辞書の作成2:FOR文でシートから取得
基本的には前節と同じであり、取得するデータをSheetから取得して辞書を作成しました。
[IN]
Sub Test2()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
'データを取得するシートをWithステートメントで指定
With Worksheets("Sheet1")
For i = 1 To 3
Key = .Cells(i, 1).Value 'A列のデータ
Value = .Cells(i, 2).Value 'B列のデータ
dict.Add Key, Value '同じ行の{A列データ:B列データ}辞書を作成
Next
End With
Debug.Print dict("BTC")
End Sub
[OUT]
2992808
5-4.辞書のデータ確認
辞書のデータ数、KEYの存在確認はそれぞれプロパティのCount, Existsを使用します。またFor Each構文を使用することで辞書のKEYをFOR文で取得できるため全データを確認できます。
[IN]
Sub Test3()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
dict.Add "BTC", 2992808
dict.Add "ETH", 209926
dict.Add "XRP", 47.845 '別パターンでデータ登録
Debug.Print dict.Count
Debug.Print dict.Exists("BTC"), dict.Exists("DOGE")
For Each Key In dict
Debug.Print "KEY", Key
Debug.Print "VALUE", dict(Key)
Next
End Sub
[OUT]
3
True False
KEY BTC
VALUE 2992808
KEY ETH
VALUE 209926
KEY XRP
VALUE 47.845
5-5.辞書のデータ抽出
辞書からのデータ抽出は"dict(<KEY>)"と記載します。サンプルは下記の通りです。
[IN]
Sub Test()
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
dict.Add "BTC", 2992808
dict.Add "ETH", 209926
dict.Add "XRP", 47.845 '別パターンでデータ登録
Debug.Print dict("BTC")
Debug.Print dict("XRP")
End Sub
[OUT]
2992808
47.845
6.オブジェクト
ブックやシートなどのオブジェクトを使用する場合は変数と定義方法が異なり、”Dim”ではなく”Set”を使用します。この時オブジェクト変数は絶対的な値は保持しておらず参照値となります。
参照中はメモリを使用するため、メモリを解放するためにはSetにNothingを代入して参照を削除します。
[オブジェクトの定義方法]
Set <オブジェクト変数名> = オブジェクト変数
[オブジェクトの参照削除]
Set オブジェクト変数 = Nothing
参考としてWorksheetオブジェクトを取得して、プロパティからシート名を取得します。
[IN]
Sub Test5()
'Sheetオブジェクトを定義
Set Sheet_1 = ThisWorkbook.Sheets("Sheet1") 'シート名から選択
Set Sheet_2 = ThisWorkbook.Sheets(1) 'シートの順番から選択
Set Sheet_3 = Sheet1 'シート名から選択
Debug.Print Sheet_1.Name
End Sub
[OUT]
Sheet1
参考資料・参考記事
あとがき
全部は書ききれないのでゆっくり更新予定