二次元配列のVBAの書き方がわからない!

このQ&Aのポイント
  • VBAにおける二次元配列の書き方がわからない人のために、具体的なコード例を紹介します。
  • Sub 二次元()内で、配列を格納する変数を増やすことで二次元配列を表現することができます。
  • Sub 二次元()では、数値とアルファベットを別々に取り出すことができます。
回答を見る
  • ベストアンサー

二次元配列のVBA

二次元配列のVBAの書き方がよくわからないのですが、 私が作ったサンプルプログラムのSub 二次元()において 二次元配列で表すにはどうすればいいのでしょうか? Sub 二次元()では 配列を格納する変数はtmpしか使っていませんが もう一つ配列を格納する用の変数を作ればいいのでしょうか? 数字とアルファベットは別々に取り出したいです。 ----------------------------------------------------- Sub 一次元() Dim myStr As String Dim tmp As Variant Dim i As Long For i = 1 To 5 myStr = myStr & "," & i Next myStr = Mid(myStr, 2) tmp = Split(myStr, ",") For i = LBound(tmp) To UBound(tmp) Debug.Print tmp(i) Next i End Sub Sub 二次元() Dim myStr As String Dim tmp As Variant Dim i As Long For i = 1 To 5 myStr = myStr & "," & i & "と" & Chr(64 + i) Next myStr = Mid(myStr, 2) tmp = Split(myStr, ",") For i = LBound(tmp) To UBound(tmp) Debug.Print tmp(i) Next i End Sub

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

こんにちは。 ソースの概要(条件と具体的な処理内容)と最終的な出力方法 が判らないと何とも言えない面もありますが、 差し当たり需要がありそうな処理例で4例挙げてみます。 私の第一感では、/// j あたりのことをお求めなのかな?と思いましたが、 他の例も理解した上で目的に照らして使い分けて頂ければ、と。 例えば、/// a と /// j では、 数値なのか数字(文字列)なのか、どちらにも容易に切り替え可能です。 Split()関数に拘らずにArray()関数を使うなら、/// b と /// b でも 同様に扱えます。 ただ、区切り文字を挟んで連結された文字列がソースになる処理って 需要が多いですから、Split()関数じゃないと困る?こともあろうかと。 最終的には  matrix(1 To 5, 1 To 2) というサイズの二次元配列を扱うように書いていますが、 X方向のサイズ「2」が固定でない場合は、工夫が必要です。 具体的な条件を説明できるようでしたら、補足してみて下さい。 ' ' /// a ' ' 予め定義した二次元配列に直接格納する場合 Sub ReW9109291a() Dim matrix() As Variant Dim nYSize As Long Dim i As Long Dim j As Long  nYSize = 5  ReDim matrix(1 To nYSize, 1 To 2)  ' ' 二次元配列に直接格納する  For i = 1 To nYSize '  matrix(i, 1) = i ' option 1/2 数値として扱う場合   matrix(i, 1) = CStr(i) ' option 2/2 数字文字列値として扱う場合   matrix(i, 2) = Chr$(64 + i)  Next i  ' ' 二次元配列の全要素をイミディエイトウィンドウに出力  For i = LBound(matrix) To UBound(matrix)   Debug.? "-"; i; "-",   For j = LBound(matrix, 2) To UBound(matrix, 2)    Debug.? matrix(i, j),   Next j   Debug.?  Next i  ' ' デバッグ・トレース  Stop ' ローカルウィンドウで変数の中身を(構造と要素について)確認  ' ' 確認が済んだら[中断(デバッグ)モード]を[F5キー]で抜けて、以下を実行  ' ' 出力例 セル範囲に出力  With Cells(1).Resize(UBound(matrix), UBound(matrix, 2))   .NumberFormat = "@" ' option 数字(文字列)として扱う場合   .Value = matrix()  End With End Sub ' ' /// b ' ' Split()を使う例:二段配列(ジャグ配列) (数字(文字列)として扱う場合) Sub ReW9109291b() Dim matrix As Variant Dim nYSize As Long Dim i As Long Dim j As Long  nYSize = 5  ReDim matrix(1 To nYSize)  ' ' 連結文字列を取得(作成)して、一次元配列に格納  For i = 1 To nYSize '  matrix(i) = i & "," & chr$(64 + i)   matrix(i) = CStr(i) & "," & Chr$(64 + i) ' 省略せずに書く場合  Next i  ' ' 一次元配列に格納された連結文字列をSplit()関数で一次元配列にして、  ' ' 一次元配列の要素が一次元配列である二段配列(ジャグ配列)として配列を書き換える  For i = 1 To nYSize   matrix(i) = Split(matrix(i), ",")  Next i  ' ' 二段配列の全要素をイミディエイトウィンドウに出力  For i = LBound(matrix) To UBound(matrix)   Debug.? "-"; i; "-",   For j = LBound(matrix(i)) To UBound(matrix(i))    Debug.? matrix(i)(j),   Next j   Debug.?  Next i  Stop  ' ' 出力例  ' ' 一次元配列の要素が一次元配列である二段配列(ジャグ配列)を二次元配列に変換  matrix = Application.Transpose(Application.Transpose(matrix))  With Cells(1).Resize(UBound(matrix), UBound(matrix, 2))   .NumberFormat = "@" ' option 数字文字列値   .Value = matrix  End With End Sub ' ' /// c ' ' Split()を使う例:各行ごとに連結文字列を一旦一次元配列に格納しておいて、二次元配列に変換 (数字文字列値として扱う場合) Sub ReW9109291c() Dim ary() As String Dim matrix() As Variant Dim tmp As Variant Dim nYSize As Long Dim i As Long Dim j As Long  nYSize = 5  ReDim ary(1 To nYSize)  ' ' 一次元配列に連結文字列を格納する  For i = 1 To nYSize   ary(i) = CStr(i) & "," & Chr$(64 + i)  Next i  ReDim matrix(1 To nYSize, 1 To 2)  ' ' 一次元配列の要素である連結文字列をSplit()関数で配列として分けてから二次元配列に格納する  For i = 1 To nYSize   tmp = Split(ary(i), ",")   For j = 1 To 2    matrix(i, j) = tmp(j - 1)   Next j  Next i  ' ' 二次元配列の全要素をイミディエイトウィンドウに出力  For i = LBound(matrix) To UBound(matrix)   Debug.? "-"; i; "-",   For j = LBound(matrix, 2) To UBound(matrix, 2)    Debug.? matrix(i, j),   Next j   Debug.?  Next i  Stop  ' ' 出力例  With Cells(1).Resize(UBound(matrix), UBound(matrix, 2))   .NumberFormat = "@" ' option 数字(文字列)   .Value = matrix()  End With End Sub ' ' /// j ' ' 格納する文字列を連結しながら文字列変数に格納してEvalateメソッドでダイレクトに二次元配列にする例 Sub ReW9109291j() Dim matrix As Variant Dim buf As String Dim nYSize As Long Dim i As Long Dim j As Long  nYSize = 5  ' ' 文字列を連結して文字列型変数に格納  For i = 1 To nYSize '  buf = buf & ";" & i & "," & """" & chr$(64 + i) & """" ' option 1/2 数値   buf = buf & ";" & """" & i & """" & "," & """" & Chr$(64 + i) & """" ' option 2/2 数字文字列値  Next i  ' ' 連結文字列をExcel数式の配列表記として整形  buf = "{" & Mid$(buf, 2) & "}"  Debug.? "Excel数式: "; buf  ' ' Evaluateメソッドで、二次元配列を取得  matrix = Application.Evaluate(buf)  ' ' 二次元配列の全要素をイミディエイトウィンドウに出力  For i = LBound(matrix) To UBound(matrix)   Debug.? "-"; i; "-",   For j = LBound(matrix, 2) To UBound(matrix, 2)    Debug.? matrix(i, j),   Next j   Debug.?  Next i  Stop  ' ' 出力例  With Cells(1).Resize(UBound(matrix), UBound(matrix, 2))   .NumberFormat = "@" ' option 数字文字列値   .Value = matrix  End With End Sub ' ' ///

RHVVVZOPZKZIA
質問者

お礼

ありがとうございました。

その他の回答 (1)

回答No.1

001;AA1;BB1;CC1<;> 002;AA2;BB2;CC2<;> 1、まず、用意するデータは二次元配列であること。 2、次に、二次元データを取り込むSplits()を自作すること。 既存のSplit()は一次元配列でデータを格納します。ですから、二次元配列でデータを取り込むには、(Array()を利用しないのであれば)そういう関数であるSplits()を自作するしかありません。 【行と列の二次元データを取り込むSplits()の仕様】 1、データが完全な二次元であるかを検証する。 2、検証で確認した行数と列数とを変数として記憶する。 3、二次元配列変数を行数と列数とで再宣言する。 4、行データを一次言配列tmpRows()に代入する。 5、行(R)と列(C)との二重ループで二次元配列変数に取り込むことを開始。 FOR I=0 TO RowTotal   FOR J=0 TO ColTotal     strDatas(I, J) = CutStr(tmpRows(I), ";", J+1)   NEXT J NEXT I こんな感じで行と列の二次元データを取り込むSplits()は書くことが出来ると思います。 PS、CutStr()は次のようです。 Public Function CutStr(ByVal Text As String, _             ByVal Separator As String, _             ByVal N As Integer) As String   Dim strDatas() As String      strDatas = Split("" & Separator & Text, Separator, , 0)   CutStr = strDatas(N * Abs(N <= UBound(strDatas))) End Function CutStr()を利用すれば、Splits()のメインは5行で書けるかもです。

RHVVVZOPZKZIA
質問者

お礼

ありがとうございました。

関連するQ&A

  • vbaで配列に値を格納する場合

    vbaで配列に値を格納する場合 変数の宣言はどちらを使った方が良いのでしょうか? Sub Sample1() Dim i As Long Dim myStr As String Dim tmp() As String myStr = "a,i,u,e,o" tmp = Split(myStr, ",") End Sub か Sub Sample1() Dim i As Long Dim myStr As String Dim tmp As Variant myStr = "a,i,u,e,o" tmp = Split(myStr, ",") End Sub でも問題なく動くのですが、 Variant型での宣言はあまりしない方が良いですか? あと Dim tmp() As String ならエラーにならないのですが Dim tmp As String だとエラーになってしまう理由がよくわからないので教えて頂けますか?

  • 変数を配列に格納する時に、二つの条件を指定すること

    変数を配列に格納する時に、二つの条件を指定することはできますか? VBAです。 Private Sub test() Dim i As Long Dim Str As String Dim tmp As Variant Str = "a,i,u-e-o" tmp = Split(Str, ",") '配列に格納する For i = LBound(tmp) To UBound(tmp) Debug.Print tmp(i) Next i End Sub の場合、結果が a i u-e-o になってしまいます。 tmp = Split(Str, "," or "-") のようなことをして a i u e o と表示させたいです。 "a,i,u-e-o"を"a,i,u,e,o"にすることはできません。ご教授よろしくお願いします。

  • VB バリアント型の配列の例について

    長々と失礼します。私の使用している教科書に 「バリアント型の2次元配列」と「バリアントに2次元配列を代入」というのを組み合わると「行列i要素とする行列」たとえば 2 5 9 4 1 8 7 3 6 1 5 9 8 0 1 6を的確に表現できます。 と書いており、下のように書かれているのですが上のような配列を表示しません。どこが間違っているのでしょうか?そもそも上のように表示できるのか理解に苦しんでおります Option Base 1 Private Sub Command1_Click() Dim a(2,2) As Variant Dim c(2,2) As Integer For i = 1 To 2 For j = 1 To 2 For p = 1 To 2 For q = 1 To 2 c(p,q) = p + q + i * j Next q Next p a(i,j) Next j Next i For i = 1 To 2 For p = 1 To 2 For j = 1 To 2 For q = 1 To 2 Print a(i,j)(p,q), Next q Next j Print Next p Next i End Sub

  • 動的配列の後始末?

    以下のサブルーチンで、lines()と動的配列を定義して、Splitでデータを入れたのですが、このサブルーチンが終了すると、lines()はデータも含めて解放されるのでしょうか? 極端な話、1億回このサブルーチンを呼ぶと、メモリーリークするのでしょうか? それと、VB6やVB.NETでは、For文・For Each文のどちらを使う方が良いのでしょうか? Sub test() Dim lines() As String lines = Split(Data, vbCrLf, -1, vbBinaryCompare) Dim i As Integer For i = LBound(lines) To UBound(lines) MsgBox ("for=[" & lines(i) & "]") Next i Dim s As Variant For Each s In lines MsgBox ("for each=[" & s & "]") Next End Sub

  • InternetExplorer.Applicat

    Sub test1() Dim objIE As Object Dim i As Long Dim MyRow As Long Dim Str As String Dim tmp As Variant Set objIE = CreateObject("InternetExplorer.Application") objIE.Navigate "http://oshiete.goo.ne.jp/" objIE.Visible = True Do While objIE.Busy = True DoEvents Loop Str = objIE.Document.Body.innerHTML 'ソースを抜き出す tmp = Split(Str, Chr(10)) '配列に格納する MyRow = 1 '初期値 For i = LBound(tmp) To UBound(tmp) Cells(MyRow, 1) = tmp(i) MyRow = MyRow + 1 Next i objIE.Quit Set objIE = Nothing End Sub ************************************************** Sub test2() Dim objIE As Object Dim Str As String Dim tmp As Variant Dim i As Long Dim MyRow As Long Set objIE = CreateObject("MSXML2.XMLHTTP") objIE.Open "GET", "http://oshiete.goo.ne.jp/", False objIE.Send Str = objIE.responseText 'ソースを抜き出す tmp = Split(Str, Chr(10)) '配列に格納する MyRow = 1 '初期値 For i = LBound(tmp) To UBound(tmp) Cells(MyRow, 1) = tmp(i) MyRow = MyRow + 1 Next i Set objIE = Nothing End Sub ************************************************** 上記の二つのコードは どちらもVBAでHTMLソースをエクセルに書き出すコードなのですが 結果が違います。 なぜなのでしょうか? 実際のソースを確認したら CreateObject("MSXML2.XMLHTTP") の方が正しかったです。 CreateObject("InternetExplorer.Application") は何が取得されてるのでしょうか?

  • 2次元配列を返す関数について

    VB6でExcelのMMULTのような関数が欲しかったので作って見ました。 関数内で配列をRedimで確保して戻り値として返すのですが、このような方法でメモリーリークなど発生する心配はないでしょうか? '行列の掛け算 Public Function mtxMult(ByRef mx1() As Double, ByRef mx2() As Double) As Double() Dim r, c, i, r1, c1, r2, c2 Dim res() As Double '行と列の最大値を得る r1 = UBound(mx1, 1) c1 = UBound(mx1, 2) r2 = UBound(mx2, 1) c2 = UBound(mx2, 2) If c1 <> r2 Then Exit Function ReDim res(0 To r1, 0 To c2) '答えの配列を確保 '各要素を掛ける For r = 0 To r1 For c = 0 To c2 res(r, c) = 0 For i = 0 To c1 res(r, c) = res(r, c) + mx1(r, i) * mx2(i, c) Next i Next c Next r mtxMult = res End Function '動作確認 Private Sub Command1_Click() Dim mx1(0 To 1, 0 To 1) As Double Dim mx2(0 To 1, 0 To 1) As Double Dim res() As Double Dim r As Integer List1.Clear mx1(0, 0) = 1 mx1(0, 1) = 2 mx1(1, 0) = 3 mx1(1, 1) = 4 mx2(0, 0) = 5 mx2(0, 1) = 6 mx2(1, 0) = 7 mx2(1, 1) = 8 res = mmult(mx1, mx2) For r = 0 To 1 List1.AddItem res(r, 0) & " , " & res(r, 1) Next r End Sub ところで、質問のソースコードのインデントを保持する方法はないでしょうか?

  • VBAの動的配列について

    いつもお世話になっております。 エクセルVBAを学習中の者です。 動的配列についてお伺いします。 添付資料を見て頂きたいのですが、 シート名1~4に同一レイアウトの表があります。 これらの表をを2次元配列に格納し、その後、同一レイアウトのシートに一括転記したいと考えています。 転記の事を考えて、条件としては、 シート1から2行目以降のデータを配列『data』に格納、変数『dataCnt』が転記先の行番号と同じになるように考えています。 当初は、配列の定義を『Dim data(100,3) As Variant』と、多めに要素数を定義して、コードを記述していました。 正直、凄く気持ちが悪い感じでした・・・ 最近、動的配列を学習しまして、 シートごとにデータの行数を変数『lastRow』に格納して、配列を再定義して【データ数=要素数】とならないか? と思い、下記のようなコードを書いてみました。 が、『ReDim Preserve~』で実行エラーが発生してしまいます。 原因がなぜかわかりません! そもそも、動的配列はこのような使い方は出来ないのでしょうか? Sub テスト() Dim data() As Variant Dim x As Long Dim i As Long Dim ii As Long Dim lastRow As Long Dim dataCnt As Long dataCnt = 2 For x = 2 To 5 Worksheets(x).Activate lastRow = Cells(Rows.Count, 1).End(xlUp).Row If x = 2 Then ReDim data(2 To lastRow, 3) Else ReDim Preserve data(2 To dataCnt + lastRow - 1, 3) End If For i = 2 To lastRow For ii = 1 To 3 data(dataCnt, ii) = Cells(i, ii) Next ii dataCnt = dataCnt + 1 Next i Next x End Sub どなたかご指導をよろしくお願いいたします。

  • エクセルVBAで配列?

    以下は、文字列"t", "e", "s", "t"を配列に取り込み、セルに表示する例ですが、 ar = Array("t", "e", "s", "t") なら作動しますが、セル範囲から取り込もうと、 ar = Range("A1:D1").Value とするとエラーになります。 どうしてでしょうか? Sub test() Dim ar As Variant Dim n As Integer ar = Array("t", "e", "s", "t") 'ar = Range("A1:D1").Value For n = LBound(ar) To UBound(ar) Cells(n + 1, 5) = ar(n) Next n End Sub

  • 配列変数 インデックス番号の最小値

     特に指定しない場合、配列変数のインデックス番号の最小値は0から始まるはずですが、下記のプロシージャでは、abの最小インデックス番号は1,2次元とも「0」でなく「1」から始まります(ウォッチ式で見ても「1」から始まっています)。 「0」から始まらない理由が分かりません。 ご教授を よろしくお願いいたします。 Public Sub セル参照() ' "A1:B10"のセル範囲のデータを順番にメッセージボックスに表示する。 Dim ab As Variant Dim i As Integer, j As Integer ab = Worksheets("Sheet1").Range("A1:B10").Value For i = 1 To UBound(ab, 1) For j = 1 To UBound(ab, 2) MsgBox ab(i, j) Next j Next i End Sub

  • [VBA]二次元配列を使ったsumif

    こちらの識者の方々にはいつもお世話になっています。 VBAの質問です。 環境は下記になります。 OS=windowsXP SP3 Office=Excel2003(11.8347.8403) SP3 vbaでワークシート関数でいうsumifにあたる計算をしたいのですが、自分なりに二次元配列でコードを書いたものの、それでも時間がかかりすぎるため質問させていただきます。 :Sheet1      4月   5月   6月   7月 りんご  20    10   31 みかん  50        40    20 バナナ  35    15   20 りんご       52   50    65 ぶどう           32    63 みかん  21        23    50 のようなデータが約40,000行存在します。 これをSheet2に      4月   5月   6月   7月 りんご  20    62   81   65 みかん  71    0    63   70 バナナ  35    15   20    0 ぶどう  0     0   32    63 のような形で集計したいのです。 自分で書いたコードは下記です。 Option Explicit Option Base 1 Sub test()  Dim SourAry As Variant  Dim DestAry As Variant  Dim SourEndRow As Long  Dim DestEndRow As Long  Dim i As Long  Dim j As Long  Dim k As Long  Dim TTL As Long  Application.ScreenUpdating = False  SourEndRow = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row  DestEndRow = Sheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row  SourAry = Sheets("Sheet1").Range("A2:E" & SourEndRow).Value  DestAry = Sheets("Sheet2").Range("A2:E" & DestEndRow).Value  For i = 2 To 5   For j = 1 To UBound(DestAry)    For k = 1 To UBound(SourAry)     If SourAry(k, 1) = DestAry(j, 1) Then TTL = TTL + SourAry(k, i)     DestAry(j, i) = TTL    Next k    TTL = 0   Next j  Next i  Sheets("Sheet2").Range("A2:E" & DestEndRow).Value = DestAry  Application.ScreenUpdating = True End Sub これでも一応希望通りの結果は得られるのですが、40,000行ともなると配列で処理したとしてもとても時間がかかってしまいます。 ご教示いただきたいことは、もっと効率のいいコードなのですが、実は実際のデータはSheet1とSheet2のA列のデータは昇順で並んでおります。 後学のためにもしよろしければ下記2パターンを教えて戴けませんでしょうか。 1.キーとなるフィールドが昇順で並んでいる場合 2.キーとなるフィールドの順番がばらばらで、かつ並び替えることができない場合(A列総当たり) 2.のパターンの場合、コードによると思いますが、総当たりよりかはやはり並び替えた方が効率はいいものなのでしょうか? 質問に不備不足等ございましたらご指摘ください。 ご面倒お掛けしますがよろしくお願いします。

専門家に質問してみよう