【VBA】備忘録・大雑把な性格の私にぴったりだったCollectionの話がしたい
少し前まで食わず嫌いだったら「Collection」と「Dictionary」
アタイには使えないわ!無理無理と思ってたけど、慣れてみたら簡単で超便利ウルトラサランラップだったので備忘録も兼ねて記録を残したいと思います。
月曜の病み上がり気味の変なテンションで書いているのですが、温かい目で見てくださいね。
Collectionとは
以下、丁寧な説明を他サイトから引用させていただきます。
Collectionオブジェクトは、1つのオブジェクトとして参照できる複数の要素の集合です。Collectionオブジェクトを利用すると、互いに関連付けられた複数の要素を 1 つのオブジェクトとして参照できます。
つまり、文字列、数値、オブジェクトを要素とした独自のコレクション(オブジェクト)を作成できるという事です。
引用元:エクセルの神髄 https://excel-ubara.com/excelvba1/EXCELVBA358.html
うーん。なんでもぶっこめる箱?ってイメージ。とりあえず使ったことのないものに敬遠するのが人間の性。
なんでも格納できるものって言ったらやっぱり配列ですよね!
Dim myArray() as Variant : myArray = Array(1,Date,3,4,"str")
みたいにガチャホラガチャホラ突っ込んであとで頭でいじいじしながら使うイメージ。頭の中のイメージと実際の動きがピタッとあった時の快感がマジでultra soul
Google App Scriptの学習を経て、プログラムは基本的に配列にやるのが相場なんやなとカツオの中では理解したのでとりあえずなんでも配列にする癖がつきましたがVBAの配列って面倒!って思っています。
動的配列につきもののReDimステートメント
ReDimステートメント。これがだるい。二次元配列の場合だとなおさら使いづらい。
※またまたきれいに他サイトを引用させていただきます
Office TANAKA
ReDimステートメント
構文
ReDim [Preserve] varname(subscripts)[As type]
Preserveは省略可能です。既存データを保持したまま要素数を変更します。varnameには、要素数を変更する動的配列変数名を指定します。
subscriptsには、変更する要素数を指定します。
typeは省略可能です。配列変数のデータ型を指定します。
解説
動的配列の要素数や次元数を変更します。
動的配列とは、配列変数の宣言時に要素数を指定せず空の括弧を付けた配列変数です。
キーワードPreserveを使うと、すでに配列内に持つデータを失うことなく要素数を変更することができます。
要素数が決まっていない、または要素が随時増えるとかそういう事態に陥ったときに、いちいち
ReDim Preserve ~
これが嫌なんですわ。しょっちゅう間違えるし、多次元配列だと
1. 最後以外の次元のインデックスが同じ:二次元配列なら一次元目のインデックスは変更できません。
2. 最後の次元の最小インデックスが同じ:一次元配列のときと同じ条件です。
https://www.tipsfound.com/vba/02016
一次元目を行(Row)のイメージで二次元目を列(Column)のイメージでやっているからなおのことわかりづらい。
※察していただけるかと思いますが最終的に二次元配列はRangeにぶっこむのが私の定番です
生意気にもPythonを使い始めた私ですが動的なWebページのテーブル要素の取得ってこんな感じなんですよね。
from selenium import webdriver
from selenium.webdriver.common.by import By
tableElem = driver.find_element_by_id(id)
trs = tableElem.find_elements(By.TAG_NAME, "tr")
# ヘッダなどに合わせて開始行はrangeで指定する
arr = []
for i in range(1,len(trs)):
tds = trs[i].find_elements(By.TAG_NAME, "td")
line = []
for j in range(0,len(tds)):
line.append(tds[j].text)
arr.append(line)
#ここで arrに二次元配列が完成されて格納される
このやり方がなんとも素直
arr----------------------------------------------
1 [ line ]
2 [ line ]
3 [ line ]
…
----------------------------------------------
書き方デタラメ~って
松尾さん風に言っちゃう感じですよ
こんなにシンプルだととにかくポコスカ配列に突っ込める。要素の定義や組み立て方で悩むこともそんなない。
これをVBAでやりたい。それがスタートです。
私のやりたいことはCollectionに配列をぶっこんでいくことで解決する
さっき書いたPythonの例をVBAでやる場合、そっくりそのままCollectionでやればいいんじゃないって気づきました。(多分先人たちはとっくに気付いているのでしょう)
Collectionを使うときは特段必要な参照設定はありません。
宣言は二パターン
① 特徴:一行で済む。Collectionの中身の初期化が途中でできない
Dim col As New Collection
② 特徴:二行になるがSetで初期化が可能。
Dim col As Collection
Set col = New Collection
# 最後に Set col = Nothing
両方場合に合わせて書き方変えればいいと思います。
Pythonでやっていたやり方をVBA Verでアレンジしてやってみる
※Dir関数でファイルの一覧を取得するときとか
Dim col As New Collection
#まずヘッダー行を作って
Dim rowArray as Variant : rowArray = Array("No","Path","Filename","Column4","Column5")
col.Add rowArray
Const Path As String = "C:\Sample\"
Const cnsDir As String = "\*.*"
#そのあとLoopで特定のテーブルから条件に則って必要なデータとったりして追加しています
Dim strFilename As String : strFilename = Dir(Path & cnsDir , vbNormal)
Dim i as Integer : i = 1
Do While strFilename <> ""
rowArray = Array(i , Path & cnsDir , strFilename , "何か入れたいやつ" , "何か入れたいやつ")
col.Add rowArray
strFilename = Dir()
i = i + 1
Loop
可変のものを取得するときとか便利ですよね!これぞやりたかったこと!
最終的にRangeにそのまま突っ込むにはひと手間が必要で
ReDim myRange( 1 to col.Count , 1 to (Ubound(rowArray) + 1)
Dim c as Variant
Dim RowNum as Integer : RowNum = 1
For Each c in col
For i = Lbound(rowArray) to Ubound(rowArray)
myRange(RowNum , i + 1) = c(i)
Next i
RowNum = RowNum + 1
Next c
とひと手間かまさなきゃいけないわけです。
※ごめんなさい。上記のコードテスト未済です。
とはいえ会社でフォルダの整理がしたい!というオーダーに対して整理されたコードが書けました!
食わず嫌いでもっと成長できればいいですね・・・。
最近は具合悪かったり、ふらふらしたりで集中できない。
季節の変わり目。皆様も体調にはお気を付けください。
ド級の下ネタですが最高に元気が出るお勧めの動画を挙げます。最近毎日聞いています。どぶろっくの沼にハマりました。
※下ネタ嫌いな人は見ないでね!
この記事が気に入ったらサポートをしてみませんか?