- ベストアンサー
Excel VBA 2次元配列を使った具体サンプル
よろしくお願いします。 Excel VBAの初学者です。 今、配列の勉強をしているのですが、2次元配列を使った具体的なサンプルソースをご存知でしたら教えてください。 ネットで検索しても基本的なこと、抽象的な表現をしたものしから見付けれられず、なんか具体性に乏しいため、今一つ配列についての理解が進められないでいます。 何か、良いサンプルがありましたら紹介されているサイトや本等、教えてください。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
(2/2連投) 以下、サンプル。 ◆◆準備 空のシートを2つ用意して、 それぞれシート名を"詳細"、"集計"としてください。 下記サンプル「元の表」(正味4行)はそのままコピーして、 "詳細"シートのA1セルにテキストデータとして貼付けて、 [データの区切り位置]機能で展開して使います。 "集計"シートは空のままです。 "詳細"シートの「元の表」 と "集計"シートの各「Step」を記録した イメージ画像を添付します。見づらいようでしたら一旦PCに落としてから拡大してみてください。 元の表 シート : 詳細 ' ' ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 科目 ・国 ・国 ・国 ・国 ・数 ・数 ・数 ・数 ・英 ・英 ・英 ・英 ・社 ・社 ・理 ・理 ・選1 ・選1 ・選2 ・選2 ・選3 ・選3 番号 1 2 3 4 1 2 3 4 1 2 3 4 3 4 1 2 1 3 2 3 1 4 名前 佐藤 高橋 鈴木 田中 佐藤 高橋 鈴木 田中 佐藤 高橋 鈴木 田中 鈴木 田中 佐藤 高橋 佐藤 鈴木 高橋 鈴木 佐藤 田中 点数 75 59 92 95 89 73 68 96 100 72 78 61 73 75 82 86 67 62 93 83 75 80 ' ' ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー ※同一科目名が連続する部分はセルの結合を適用する想定で書いています。 処理後の表(結果) シート : 集計 ' ' ーーーーーーーーーーーーーーーーーーーー 番号 名前 科目 点数 科目数 1 佐藤 ・国・数・英・理・選1・選3 488 6 2 高橋 ・国・数・英・理・選2 383 5 3 鈴木 ・国・数・英・社・選1・選2 456 6 4 田中 ・国・数・英・社・選3 407 5 ' ' ーーーーーーーーーーーーーーーーーーーー ◆◆テスト用サンプル 敢えて詳細な解説は書きません。 コードを読む、ようにしてください。 ' ' ========================= Sub Re8247882test() Dim mtxS As Variant ' 二次元配列、インプット Dim mtxP As Variant ' 二次元配列、アウトプット Dim arrTmp As Variant ' 一次元配列、仮設 Dim sTmp As String ' 科目名 Dim tnP As Long ' 人数 Dim ubS2 As Long ' レコード件数(配列のXSize(横方向サイズ)) Dim nNum As Long ' IDを拾う Dim i As Long Dim j As Long Sheets("集計").Select ' ★ Range("A1:E5").ClearContents ' ★ MsgBox "処理開始" ' ★ tnP = 4 mtxS = Sheets("詳細").Cells.CurrentRegion ubS2 = UBound(mtxS, 2) ReDim mtxP(0 To 4, 1 To 5) ' ' ★ Step 1 ' ' 項目名を一旦一次元配列に。 arrTmp = Split(" 番号 名前 科目 点数 科目数") ' ' arrTmp(0) = Empty ' ' arrTmp(1) = 番号 ' ' arrTmp(2) = 名前 ' ' arrTmp(3) = 科目 ' ' arrTmp(4) = 点数 ' ' arrTmp(5) = 科目数 For j = 1 To 5 Debug.Print "arrTmp(" & j & ") = " & arrTmp(j) mtxP(0, j) = arrTmp(j) Next j Range("A1:E5").Value = mtxP ' ★ MsgBox "★ Step 1" ' ★ Stop ' ★ ' ' ★ Step 2 For i = 1 To 4 mtxP(i, 1) = i Next i Range("A1:E5").Value = mtxP ' ★ MsgBox "★ Step 2" ' ★ Stop ' ★ ' ' ★ Step 3 For i = 1 To 4 mtxP(i, 2) = mtxS(3, i + 1) Next i Range("A1:E5").Value = mtxP ' ★ MsgBox "★ Step 3" ' ★ Stop ' ★ ' ' ★ Step 4 For j = 2 To ubS2 If mtxS(1, j) <> "" Then sTmp = mtxS(1, j) nNum = mtxS(2, j) mtxP(nNum, 3) = mtxP(nNum, 3) & sTmp Next j Range("A1:E5").Value = mtxP ' ★ MsgBox "★ Step 4" ' ★ Stop ' ★ ' ' ★ Step 5 For j = 2 To ubS2 If mtxS(1, j) <> "" Then sTmp = mtxS(1, j) nNum = mtxS(2, j) mtxP(nNum, 4) = mtxP(nNum, 4) + mtxS(4, j) Next j Range("A1:E5").Value = mtxP ' ★ MsgBox "★ Step 5" ' ★ Stop ' ★ ' ' ★ Step 結果 For j = 2 To ubS2 If mtxS(1, j) <> "" Then sTmp = mtxS(1, j) nNum = mtxS(2, j) mtxP(nNum, 5) = mtxP(nNum, 5) + 1 Next j Range("A1:E5").Value = mtxP MsgBox "結果" ' ★ End Sub ' ' ========================= ' ' (' ★の行は提示用。処理内容とは無縁。) ◆◆実践サンプル 基本的にテスト用に書いたものなのですが、 テスト用サンプルでは、わざと分けて書いているものを纏めたものです。 ' ' ========================= Sub Re8247882() Dim mtxS As Variant ' 二次元配列、インプット Dim mtxP As Variant ' 二次元配列、アウトプット Dim arrTmp As Variant ' 一次元配列、仮設 Dim sTmp As String ' 科目名 Dim tnP As Long ' 人数 Dim ubS2 As Long ' レコード件数(配列のXSize(横方向サイズ)) Dim nNum As Long ' IDを拾う Dim i As Long Dim j As Long tnP = 4 mtxS = Sheets("詳細").Cells.CurrentRegion ubS2 = UBound(mtxS, 2) ReDim mtxP(0 To 4, 1 To 5) ' ' Step 1 arrTmp = Split(" 番号 名前 科目 点数 科目数") For j = 1 To 5 Debug.Print "arrTmp(" & j & ") = " & arrTmp(j) mtxP(0, j) = arrTmp(j) Next j ' ' Step 2, 3 For i = 1 To 4 mtxP(i, 1) = i mtxP(i, 2) = mtxS(3, i + 1) Next i ' ' Step 4, 5, 結果 For j = 2 To ubS2 If mtxS(1, j) <> "" Then sTmp = mtxS(1, j) nNum = mtxS(2, j) mtxP(nNum, 3) = mtxP(nNum, 3) & sTmp mtxP(nNum, 4) = mtxP(nNum, 4) + mtxS(4, j) mtxP(nNum, 5) = mtxP(nNum, 5) + 1 Next j Sheets("集計").Range("A1:E5").Value = mtxP End Sub ' ' =========================
その他の回答 (8)
- cj_mover
- ベストアンサー率76% (292/381)
#7、8、cjです。 書き忘れがあったので補足します。 テスト用サンプルを実行する際は、 VBE(Visual Basic Editor)を表示し、 テスト用サンプルにカーソル(キャレット)を当てた状態で F5キーで実行。 (以下繰り返し) MsgBoxが表示されたら、シート内容を確認して、Enterキー([OK]) StopステートメントでVBEに表示が戻ったら、 ローカルウィンドウで配列変数の内容を確認して、F5キー(再実行) (以下繰り返し) という手順になります。
- cj_mover
- ベストアンサー率76% (292/381)
(1/2連投) ' ' Sample 1 ==================== Sub 二次元配列処理_基本ループ() Dim i As Long Dim j As Long Sheets("Sheet1").Select Cells.ClearContents MsgBox "二次元配列処理_基本ループ/実行" For i = 1 To 5 For j = 1 To 4 Cells(j, i) = Chr(i + j + 63) Next j Next i End Sub ' ' Sample 2 ==================== Sub 二次元配列処理_配列変数() Dim mtx(1 To 4, 1 To 5) As Variant Dim i As Long Dim j As Long Sheets("Sheet1").Select Cells.ClearContents MsgBox "二次元配列処理_配列変数/実行" For i = 1 To 5 For j = 1 To 4 mtx(j, i) = Chr(i + j + 63) Next j Next i Range("A1:E4").Value = mtx End Sub ' ' Sample 3 ==================== Sub 二次元配列処理_コレクション() Dim rng As Range Dim i As Long Dim j As Long Sheets("Sheet1").Select Cells.ClearContents MsgBox "二次元配列処理_コレクション/実行" Set rng = Range("A1:E4") For i = 1 To 5 For j = 1 To 4 rng(j, i).Value = Chr(i + j + 63) Next j Next i End Sub ' ' ========================= ' ' (以上、新規ブックのSheet1を対象にテストしてください) 以上のサンプル3点は何れも 二次元配列を扱うサンプルで、 何れも同じ結果を返すものです。 このサンプル3点の違いを理解し使い分けたり使いこなしたり 出来ることは、二次元配列を扱う上で基本的なことです。 このうち、Sample 2 Sub 二次元配列処理_配列変数() については、「配列変数を用いて二次元配列を処理」するものですが、 ”2次元配列を使った具体的なサンプルソース”と仰るのは、 こういうことなのかな??と思いました。 でも、知りたいのはサンプルソースというより、 配列変数を使う場合の特長とか、どんな場合に利点を発揮できるかとか、 配列変数の周辺の事情とか条件とか、そういった処への関心、 という話なんじゃないでしょうか。 具体例を付した配列変数と二次元配列の扱いについてのサンプル を次の投稿で、あげてみます。 技術的なポイントとして ・縦並びのレコードを横並びにトランスポーズ ・一次元配列を二次元配列にトレース ・ナンバリングをしながら配列に格納 ・IDに対応したレコードへの処理 ・配列の要素を文字列として連結しながら配列に格納 ・配列の要素の合計を加算しながら配列に格納 ・配列の要素の件数を加算しながら配列に格納 など、網羅しました。 ひとつひとつは初級の内容ですが、組み合わせると難度は高めです。 最も重要なポイントは”トレースの感覚を身に付けること”です。 (デバッグとトレースがごっちゃに解説されることが多いこの頃ですが) 配列変数の内容(要素)が処理に応じてどう変化してゆくのか、 確認しながらコーディングをチェックしていく作業過程、 これが出来るかどうかは配列変数を扱う上で必須と言ってもいい程、 非常に重要な技術的要素です。 VBAの場合は具体的に、 ブレークポイントを設けて実行したり、ステップモード実行したり、 しながら、ローカルウィンドウで、 基準となるインクリメント変数(一般に i や j などで表す変数)と 対応する配列変数の要素とが、どのように関連しながら変化していくのか、 ローカルウィンドウで確認していく、 という作業のことです。 実際に教えてみて感じたことですが、トレースを面倒臭がってやらない人 は、配列変数の習得に躓いて諦めてしまう人が殆どです。 上達の速い遅いもここら辺で決まってしまうようです。 (稀に天才的な方もいらっしゃるようですが、、、) サンプルでは、ブレークポイントを設ける代りに、 何処まで処理したか都度都度 MsgBoxに表示して、セル範囲に都度出力して 変数の内容を視覚的に捉えられるようにしました。 続けて、Stopステートメントで処理を一時停止しているので その状態でローカルウィンドウで変数の中身をチェックすれば 実践的なトレース、のトレーニングになる ように書いています。 また、 Excel VBA ならではの、配列変数(二次元)を使う醍醐味というと、 セル範囲の値を、そのまま、配列として採り込んだり、 配列変数(二次元)として処理したデータを、 一気に纏めてセル範囲へ出力したり、 出来る、という特長のことになるかと思います。 今回は、 Variant型の変数に二次元配列を格納する、 ことも重要なポイントとして書いています。 (次の投稿でサンプルを提示します)
- tsubuyuki
- ベストアンサー率45% (699/1545)
A列=あ行~J列=わ行 として五十音表を作ってみたけど・・ 良く考えたら、五十音表って右から始まるよね(汗)。 ・・・という状況(実際にあるかどうかわかりませんが)の時に 微妙に役に立つかもしれないサンプルです。 Sub Sample() Dim myList() As String '配列を宣言 Dim myRow As Long, myColumn As Long Dim i As Long, j As Long ' 行列数を確認 myRow = Cells(Rows.Count, 1).End(xlUp).Row myColumn = Cells(1, Columns.Count).End(xlToLeft).Column ' 配列の行列を、データの行列数に拡張 ReDim myList(myRow, myColumn) ' セルの内容を順に配列に格納 For j = 1 To myColumn For i = 1 To myRow Cells(i, j).Select myList(i, j) = Cells(i, j) Next i Next j ' 元の表の10行下に左右を入れ替えつつ、配列から取り出し For j = myColumn To 1 Step -1 For i = 1 To myRow Cells(i + 10, j).Select Cells(i + 10, j) = myList(i, myColumn - j + 1) Next i Next j End Sub サンプルと呼べるほど大袈裟なものではありませんが、一応。 ステップインで動かすと、何かが掴めるかもしれません。 本当は二次元配列の開始位置は「0,0」なのですが・・ 面倒なので「0,0」は無視して、「1,1」から使い始めているのが手抜きです。 まぁ要するに、他の方もおっしゃっていますが 「ワークシートのイメージそのまま」ですよ。 難しく考えるとどんどんハマりますから、簡単なところから徐々に行くのがミソです。
お礼
少しイメージがつかめてきました。 サンプルもありがとうございました。 勉強します。
- MarcoRossiItaly
- ベストアンサー率40% (454/1128)
あらら、すみません。No.4 です。long なのに int とか計算しても全く意味ありませんので、「and n = int(n)」という部分を削除してください。何度も失礼しました。
- MarcoRossiItaly
- ベストアンサー率40% (454/1128)
1 次元の配列 2 つをまとめて書けば、2 次元の配列。ベクトルを並べると行列になるのと同じですね。ショボいサンプルも載っけておきます。 Sub ArraySample() Dim a(3, 1) As String, prt As String Dim i As Integer, n As Integer a(0, 0) = "曲名" a(0, 1) = "作曲者" a(1, 0) = "運命" a(1, 1) = "ベートーベン" a(2, 0) = "アイネ・クライネ・ナハトムジーク" a(2, 1) = "モーツァルト" a(3, 0) = "幻想即興曲" a(3, 1) = "ショパン" For i = 1 To 3 prt = prt & vbCrLf & i & "……" & a(i, 0) Next i n = Application.InputBox(prompt:="曲名の番号を選んでください" & vbCrLf & prt, Title:="作曲者の表示", Type:=1) If 1 <= n And n <= UBound(a, 1) And n = Int(n) Then Range("a1").Value = a(0, 0) Range("b1").Value = a(0, 1) Range("a2").Value = a(n, 0) Range("b2").Value = a(n, 1) End If Columns("a:b").AutoFit End Sub
お礼
InputBoxもこのように作れるのですね。 とても参考になりました。 いろいろと応用が出来そうです。 ありがとうございました。
- cj_mover
- ベストアンサー率76% (292/381)
配列について概念としての理解を深めたいということでしたら、 こちらの解説が、解り易いと思います。 お求めの具体例、というのが、漠然として判りませんが、 こちらを読んでみて、それでももっと、例示が欲しい、 ということでしたら、補足してみてください。 配列研究室 http://www.clayhouse.jp/array/array.htm
お礼
サイトありがとうございました。 参考にさせていただきます。
- FEX2053
- ベストアンサー率37% (7991/21371)
ちょこちょこっと作ってみました。 A1セルにその月の初めの日 B1セルにその月の最後の日 その状態でこいつを実行すると、B4セルを頭にカレンダーを出力します。 Sub Macro() Dim D_CAL(5, 7) As Integer Dim I, J, D_DAY, D_CNT As Integer D_DAY = Weekday(Range("A1").Value) D_END = Day(Range("B1").Value) D_CNT = 1 For I = 1 To 7 If D_DAY > I Then D_CAL(1, I) = 0 Else D_CAL(1, I) = D_CNT D_CNT = D_CNT + 1 End If Next For J = 2 To 5 For I = 1 To 7 D_CAL(J, I) = D_CNT D_CNT = D_CNT + 1 If D_CNT > D_END Then Exit For Next Next Range("A3").Select For I = 1 To 7 For J = 1 To 5 Selection.Offset(J, I).Value = D_CAL(J, I) Next Next End Sub
お礼
ありがとうございました。 勉強します。
- masatsan
- ベストアンサー率15% (179/1159)
具体的サンプルはありませんが EXCELのシートそのものは2次元配列です。 A,B,C,,,列を 1,2,3列と考えればイメージ湧きませんか?
お礼
ありがとうございました。
お礼
cj_mover様 私の拙い質問にこんなにも回答いただいて恐縮至極です。 仰る通り、どういうデータ、場面でどういうアウトプットをする時に配列が有効なのか、ということがイメージ出来ないでいたのですが、サンプルソースや沢山いただいた解説により理解が進められました。 基本サンプルの3点はこれは基本中の基本ですよね。 私なりに少しアレンジした形で何個かソース作って練習してみました。 明日からは、途中まで逆の流れと言うか、シートのデータを配列に取り込んで別シートに出力するソースも作っていきたいと思います。 メインのサンプルプログラムは私のPCで無事動かせています。 図解付きで進行がとても分かりやすいです。 また、Stop機能を使って経過を吟味しながらという手法も大切だと分かりました。 ローカルウィンドウなどの使い方にまだ慣れていないのですし、こちらのプログラムはまだ読みきれてない、理解し切れてないですが少しずつ進めていきたいと思います。 自分でしっかりソースが作れるまで取り組んでみます。 本当に有難う御座いました!