質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

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

Q&A

解決済

2回答

14772閲覧

VBAの2次元配列の要素数を可変にしたい

Izumo1101

総合スコア49

VBA

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

0グッド

1クリップ

投稿2019/11/14 12:12

Excelのdataというシートに膨大な行数(今はテスト用に100行ほど)、K列までのデータがあります。このデータから様々な条件で抽出をしたいと考えていまして、テスト用にL列にいくつか「〇」を打っています。
既存のデータを配列化し、その中で条件に合うもの(今回は12列目に〇のあるもの)を新しい2次元配列に入れなおす記述をしました。

VBA

1Sub 配列化して項目で抽出テスト() 2 Dim i As Long, n As Long, m As Long 3 Dim x As String 4 Dim buf() As Variant 5 Dim cnt As Long: cnt = 1 6 7 buf() = Sheets("data").Range("a2:l100").Value 8 9 10 '新配列の縦要素数のために個数mを測定 11 For n = 1 To UBound(buf(), 1) 12 If buf(n, 12) = "〇" Then 13 m = m + 1 14 End If 15 Next n 16 17 '条件にあったら新配列に入れていく 18 ReDim buf2(1 To m, 1 To 12) 19 For n = 1 To UBound(buf(), 1) 20 If buf(n, 12) = "〇" Then 21 For i = 1 To 12 22 buf2(cnt, i) = buf(n, i) 23 Next i 24 cnt = cnt + 1 25 End If 26 Next n 27 28 MsgBox buf2(4, 8) 29 30End Sub

うまく動いてMsgBox buf2(4, 8)もちゃんと表示されるのですが、
'新配列の縦要素数のために個数を測定
という新配列の1次元要素数を求める動きが不器用な気がします。buf2の要素数を可変にして、条件に見合う旧配列データを次々に追加する方法はないものでしょうか。

ご教示願います。

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

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

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

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

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

hatena19

2019/11/14 12:23

「膨大な行数」というのは、最大でどのくらいのものを想定していますか。
Izumo1101

2019/11/14 12:26

行数で言うと最大で5000行程度でしょうか。高速化と勉強のために配列に挑戦しています。
hatena19

2019/11/14 12:33

抽出後の配列の出力先はシートですか。
Izumo1101

2019/11/14 12:35

抽出後にさらに抽出はあり得ますが、最後は基本的にシートに出力するつもりです。
guest

回答2

0

ベストアンサー

高速化が目的なら、VBAでオートフィルタを使用するのが、たぶん一番高速だと思います。

Office TANAKA - Excel VBA Tips(オートフィルタ(書き方の基本)

Office TANAKA - Excel VBA Tips(オートフィルタ(結果をコピーする))


配列の要素数を動的に増やすには、ReDim Preserveを使いますが、
2次元配列では増やせるのは最後の次元のみという制限があります。
ReDim Preserve buf2(r, c) だと増やせるのは c のみ。
質問の要件では増やしたいのは、r の方ですよね。

方法1
WorksheetFunction.Transpose(行列変換関数)を使うと一次元と二次元を入れ替えることでできます。まず、r, c を入れ替えて、ReDim Preserve buf2(c, r) でrを増やせることができます。
シートに出力する前にWorksheetFunction.Transposeで入れ替えてbuf2(r, c)にしてから出力します。

ただ、WorksheetFunction.Transposeには処理できる要素数の制限があるらしいです。(5000件ぐらいなら大丈夫だと思いますが)

動的2次元配列の次元を入れ替えてシートへ出力(Transpose)|VBA技術解説

方法2
配列のサイズを想定できる最大サイズで確保しておく。
そこに条件にあう行を順に放り込んでいく。
シートに出力するときには、
出力先のセル範囲のサイズを条件に合った件数のサイズに指定して代入すれば、そのサイズ分だけ出力できる。

こちらの方がシンプルだし、高速だと思います。
ただ、余分にメモリを使うことになりますが、現在のPCの標準的なスペックなら気にする必要はないでしょう。

vba

1 ReDim buf2(1 To UBound(buf), 1 To 12) 2 For n = 1 To UBound(buf) 3 ・・・略 4 cnt = cnt + 1 5 ・・・略 6 Next n 7 8 Sheets("Outpot").Range("A1").Resize(Cnt, 12).Value = buf2

方法3

方法2と同じ考え方ですか、配列は一つだけにして、
配列内で、条件にあう行を順に前に移動させていく。
出力は方法2と同じ方法で。

方法3のコード例

vba

1Sub 配列化して項目で抽出テスト() 2 Dim i As Long, n As Long 3 Dim buf() As Variant 4 Dim cnt As Long: cnt = 0 5 6 buf() = Sheets("data").Range("a2:l100").Value 7 8 '条件にあったら前に移動 9 For n = 1 To UBound(buf, 1) 10 If buf(n, 12) = "〇" Then 11 cnt = cnt + 1 12 For i = 1 To 12 13 buf(cnt, i) = buf(n, i) 14 Next i 15 End If 16 Next n 17 Sheets("output").Range("a2").Resize(cnt, 12).Value = buf 18End Sub

この方法だとメモリを無駄に使うこともなく、シンプルかつ高速です。

投稿2019/11/14 13:24

編集2019/11/15 00:57
hatena19

総合スコア33699

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

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

0

VBA

1Option Base 1 2 3Sub 配列化して項目で抽出テスト() 4 Dim i As Long, n As Long, m As Long 5 Dim x As String 6 Dim buf() As Variant 7 Dim cnt As Long: cnt = 1 8 9 buf() = Sheets("data").Range("a2:l100").Value 10 11 Dim buf2() As Variant 12 For n = 1 To UBound(buf(), 1) 13 If buf(n, 12) = "〇" Then 14 ReDim Preserve buf2(12, myUBound(buf2, 2) + 1) 15 For i = 1 To 12 16 buf2(i, UBound(buf2, 2)) = buf(n, i) 17 Next i 18 End If 19 Next n 20 21 'ReDim Preserveでは最後の次元しか変更不可なので 22 '行数を固定し、列を増やして値を貯めたbuf2をここで 23 '行列入れ替え 24 buf3 = WorksheetFunction.Transpose(buf2) 25 26 MsgBox buf3(2, 8) 27End Sub 28 29'UBoundでは動的配列で要素0の場合、エラーが発生するため 30Function myUBound(arr() As Variant, dimension As Long) 31On Error GoTo ZERO 32 myUBound = UBound(arr, dimension) 33 Exit Function 34ZERO: 35 myUBound = 0 36End Function 37

投稿2019/11/14 13:03

otaks

総合スコア223

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問