🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

2回答

1292閲覧

VBAにおいて動的配列の初期化・データ追加のやり方は、どのようなやり方がいいのでしょうか。

xail2222

総合スコア1508

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

1クリップ

投稿2021/03/17 12:48

前提・実現したいこと

VBAにて動的配列に対してデータを追加していくときに、appendメソッド等あればよいのですがないため
UBound()を使ってReDim Preserve で配列長を伸ばしてデータをセットしていくようにしてます。

ただ、宣言した時点ではUBound()を実行するとエラーになるため別途配列長を変数で持つ等の対策が必要になるかと思います。
そこで質問です。VBAにおいて動的配列の初期化・データ追加のやり方は、どのようなやり方がいいのでしょうか。
以下の提示の中の方法からどれがいいかでもいいのでご意見教えてください。

試したこと

VBA

1 ' Variant型及びVariant型配列であればArray()関数で初期化が出来る。 2 ' UBound()も-1から始まる為 3 ' Redim t(UBound(t)+1) 4 ' t(UBound(t))="a" 5 ' としてデータを追加していける。 6 Dim t() As Variant 7 t = Array() ' 問題無し 8 Dim t2 As Variant 9 t2 = Array() ' 問題無し 10 Dim t3() As String 11 ' ReDim t3(-1) ' 実行時エラー 12 ' ReDim t3 ' 構文エラー 13 ' ReDim t3() ' 構文エラー 14 ' t3 = Array() ' 実行時エラー 15 ' Erase t3 ' UBound()で実行時エラー 16 t3 = Split("", ",") ' 問題無し。UBound()で-1が返却。私は大抵これを使って実装しています。 17 Dim t4() As Long 18 ' t4 = Split("", ",") ' 実行時エラー 19 ' ・もう一つ配列長の変数を用意する実装する 20 ' ・エラートラップでReDim Preserve t4(Ubound(t4)+1)が失敗したら 21 ' ReDim Preserve t4(0)として実装する。エラーの処理が時間かかりそう?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

良し悪しはわかりませんが、
自分はついついScripting.Dictionaryを使ってしまいますね。
.Existsが使える
.Countで数が分かる
.Keys、.Itemsで配列として取得できる
という点で扱いやすさを感じます。

VBA

1 Dim dic As Scripting.Dictionary 2 Set dic = CreateObject("Scripting.Dictionary") 3 4 dic(strItem) = 0 # 追加するデータがユニークな時 5 # または 6 dic.Add dic.Count, strItem # ユニークでない時 7

ちなみに、処理中に再度初期化をするようなときには、
自分は何となくもう一度
Set dic = CreateObject("Scripting.Dictionary")
とやることが多かったのですが、
何かの時にちょっと確かめた感じでは
dic.RemoveAll
の方が処理速度的には速いようでした。

投稿2021/03/17 22:14

編集2021/03/17 22:18
jinoji

総合スコア4592

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xail2222

2021/03/17 23:13 編集

回答ありがとうございます。 Redim人気ないですね。確かに面倒ですもんね。 >自分はついついScripting.Dictionaryを使ってしまいますね。 便利ですよね。 >Dim dic As Scripting.Dictionary >Set dic = CreateObject("Scripting.Dictionary") 気になったのですが「Dim dic As Scripting.Dictionary」としているってことは参照設定しているってことだと思うのですが、それだと「Set dic = New Scripting.Dictionary」の方が良いんじゃないのでしょうか。 CreateObjectだと毎回文字列からオブジェクトの内容を取得しなおさないといけないと思うので、処理に負荷がかかると思ってます。 >dic(strItem) = 0 カッコで書くんですね。私はdic.item(strItem)と常に書いています。 >dic.RemoveAllの方が処理速度的には速いようでした。 New Scripting.Dictionaryと比較するとどうなのでしょう。 ちょっとデータを格納してテストしてみようかな。 あ、そうだ。RedimがCollection、Dictionaryよりも使える所は 構造体の配列が出来ることです! Collection、Dictionaryでは出来ないです。たぶん どうしても構造体みたいなのをCollection、Dictionaryでしたいときはクラスを作って登録という形で 簡易に複数の値を持ちたいときは dic.Add key, Array(item1,item2) ですね
jinoji

2021/03/17 23:16

CreateObject("Scripting.Dictionary") をわざわざ使うのは、 こういう場所で他の人にコードを提示するときに身に着けた所作です。 自分がコードを書いている間は、インテリセンスを効かせたいので型指定しますが、 書き込むときには、'As Scripting.Dictionary とコメントアウトするだけで 参照設定されていない環境でも動くコードになります。
jinoji

2021/03/17 23:23

たまにですが、 dic.Add Join(Array(key1, key2), vbTab), item としたり dic.Add key, New Dictionary と親子辞書にしたりします。
xail2222

2021/03/17 23:26

確かにそうですね 参照設定の説明が必要な場合もありますし vbsにする事も簡単になりますしね まぁvbsはあまり使われなくなってるかもですがまだたまに使ってます 私にはpowershellより使い易いです
guest

0

ベストアンサー

どのようなやり方がいいか、の「いい」には、

・使うメモリーが少なくてすむのでよい
・スピードが速くてよい
・ソースコードの保守性・可読性がよい

とかいろんな評価軸があり、さらには、どんなデータをどれぐらい放り込むのか、
実際の使われかたも視野にいれると、なにも語れなくなるから、

そういう点は \(・\) ---> (/・)/コッチニ置いといて。

……で、提示の中でどれがいいかって、結局、ReDimしかないのでは。(^^;
Dim t() As Variant と t2 = Array() は多分同じでしょう。

ひとつ言えるのは、ReDim Preserveは、そこそこ計算コストが高く(内部処理で負荷が大きい)
かつフラグメンテーションが発生してリソースにも負担をかけるから、
最初に十分足りるだけの容量を確保し、それでもOVERしたときは、
1個ずつ増やすのではなく、次回増やさなくていいぐらいの数を見込んで
いっぺんに増やすのがよいと思います。

ソースコードの保守性を考えたら、
私なら ReDim を使うことなど考えず、Collection ひとつですべてすましますね。

Dim col As New Collection

(なにはともあれ、こういう点に着眼して語れる場があるっていいですね。^^)

投稿2021/03/17 13:49

FromMZ1500

総合スコア496

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xail2222

2021/03/17 14:54 編集

回答ありがとうございます。 >いろんな評価軸があり、さらには、どんなデータをどれぐらい放り込むのか 確かに用途や評価軸に応じて何がいいのかは変わってきますね。 用途による違いは動的配列かcollectionかdictionaryかの違いでしょうか。 >私なら ReDim を使うことなど考えず、Collection ひとつですべてすましますね。 なるほど。私は用途に応じて使い分けてますね。 ただCollectionはexistsメソッドがないので、Scripting.Dictionaryを使う時が多いですね。 >ReDim Preserveは(略) >いっぺんに増やすのがよいと思います。 そうでしたか。とするとどこまで入れたかという変数も合わせて使ってという感じになるでしょうか。 私は動的配列を使う場合は、いつも一つずつ増やしてました。 処理速度を気にする場合は検討事項の一つになるのですね。 >提示の中でどれがいいかって、結局、ReDimしかないのでは。(^^; 追加だけで考えるとそうなのですが、初期化も含めて考えると どうするのがいいのかな。というのが、今回の質問の本意です。 使うメモリ、スピードに関しては私の提示だとどれも同じだと思いますが 「ソースコードの保守性・可読性がよい」というのと何が推奨されているのだろうか。 私の知らないもっといい方法があるのでは?と疑問に思った次第です。 もう全部CollectionとかDictionaryの方がいい。というのも 一つの回答としてありだと思います。 大量のデータの場合はappend-onlyでMDBに格納してしまうのが良いという場合もあるかと思います。
xail2222

2021/03/19 13:13

redimに言及してくれていたのでベストアンサーにさせて頂きました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問