こんにちは。
> A/B/Cそれぞれのグループの2次元配列を作成したい。
「なぜ二次元配列に格納する必要があるのか」
または
「二次元配列に格納した後でどのような処理をするのか」
とか、
「A/B/Cそれぞれのグループのグループ名(3種類)は常に固定なのか」
といった情報が不足していて、どう答えていいか難しいです。
> ... aryA ... aryB ... aryC
それぞれの変数の型は、
As Variant なのか
As Variant() なのか
As String() なのか
説明に不備がありますので、As Variantでお応えしますが、
他の型だった場合には、手を加えないと動かないものしか書けません。
それでもまぁ出来ることはあると思って、実際に色々と書いてみる内に、
何かしらレスは書けるようになるかと試してみたのですが、
やはりもう少し具体性がないと考える事が多すぎて纏まりがつきません。
既に、コーディング(+コメント)で言えば800行超、設計の種類で20種超
書いてみましたが、お求めに副うような核心には至っていないのです。
そもそも、コーディングに関する質問(相談)という体ですが、
結局の所、全体的な設計の面で、まだ整理されていないような感じも受けます。
さしあたり3例だけ挙げてみます。
「A/B/Cそれぞれのグループのグループ名(3種類)は常に固定」
である場合について、
3つのVariant型変数(aryA, aryB, aryC)に
直接格納する例をひとまず、直接的な解答として、、、。
一応、配列に関しては、次元数や、最大・最少の添え字(サイズ)等は、
基本的に大事な情報ですので、必要十分な大きさを確保しなければなりません。
よく見かける方法としては、
行列を反転させた配列を受け皿に、X(第2次元)方向に拡張(ReDim Preserve)しながら、
格納して行って、最後に行列を再反転させるのが割と簡単ですが、
予めグループ名(3種類)が判っているのであれば、
ExcelのCountIf関数で数えてからReDimしておけば、より簡素に出来ます。
' ' ーーー
' ' ReDim + CountIf -> Matrix
Sub Re_a1() ' W9155487
Dim rngTable As Range
Dim aryKeys ' 「各グループ」名 一次元配列
Dim mtxSrc ' 「基テーブル」 二次元配列
Dim aryCnt ' 「各グループ」毎の カウント
Dim aryA, aryB, aryC ' 二次元配列 格納先
Dim i As Long, j As Long, p As Long
aryKeys = VBA.Array("A", "B", "C") ' 要確認◆グループ名3種、正確に指定
With Sheets("Sheet1") ' 要確認◆シート名? With ActiveSheet?
Set rngTable = .Range("A2:B" & .Cells(Rows.Count, "B").End(xlUp).Row)
End With
mtxSrc = rngTable.Value ' 「基テーブル」まるごと二次元配列として格納
ReDim aryCnt(UBound(aryKeys))
For i = 0 To UBound(aryKeys)
aryCnt(i) = WorksheetFunction.CountIf(rngTable.Columns(2), aryKeys(i))
Next i
Set rngTable = Nothing
ReDim aryA(1 To aryCnt(0), 1 To 2)
ReDim aryB(1 To aryCnt(1), 1 To 2)
ReDim aryC(1 To aryCnt(2), 1 To 2)
ReDim aryCnt(UBound(aryKeys))
For i = 1 To UBound(mtxSrc)
Select Case WorksheetFunction.Match(mtxSrc(i, 2), aryKeys) - 1
Case 0
p = aryCnt(0) + 1
aryA(p, 1) = mtxSrc(i, 1)
aryA(p, 2) = mtxSrc(i, 2)
aryCnt(0) = p
Case 1
p = aryCnt(1) + 1
aryB(p, 1) = mtxSrc(i, 1)
aryB(p, 2) = mtxSrc(i, 2)
aryCnt(1) = p
Case 2
p = aryCnt(2) + 1
aryC(p, 1) = mtxSrc(i, 1)
aryC(p, 2) = mtxSrc(i, 2)
aryCnt(2) = p
End Select
Next i
' ' ーー 配列変数 格納処理 ↑以上↑ ーー
' ' 処理例として 結果を新規シート上で確認する
Worksheets.Add
Range("A1:E1").Value = Array("【aryA】", , "【aryB】", , "【aryC】")
Range("A2:B2,C2:D2,E2:F2").Value = Array("[項目]", "[グループ]")
Range("A3").Resize(UBound(aryA), 2).Value = aryA
Range("C3").Resize(UBound(aryB), 2).Value = aryB
Range("E3").Resize(UBound(aryC), 2).Value = aryC
End Sub
' ' ーーー
「A/B/Cそれぞれのグループのグループ名(3種類)は常に固定ではない」
場合の話かも知れませんし、そうでなくとも、備えたものを書けば、
汎用的に使えるようになりますから、以下は固定でなくても動くものについて。
(コードは次の投稿で掲げます)
ここで、
3つの配列変数(aryA, aryB, aryC)を、どう扱うのかという疑問について。
グループ名が"A"なら、変数aryA
グループ名が"B"なら、変数aryB
グループ名が"C"なら、変数aryC
という対応関係は解るのですが、元は同一のテーブルな訳ですから、
異なる目的に使うものではなさそうに見えます。
すると、変数を参照する際にも、"A"ならaryAみたいな記述を固定的に書く、
という設計になっているのでしょうか。
だとすると今度は、aryA(any,2)にわざわざひとつずつ"A"を格納しておく必要
が、どんな理由なのかも解り難いです。
外部のアプリケーションに配列を渡す場合でも、配列でなければならない、という
ことは滅多にないですし、
Excelシートに出力する為ならAdvancedFilterだけで片付きますから配列は不要ですし、、、。
私が想定したのは、
配列への参照を動的に(その配列を参照するか)変化させたい、
という要求についてです。
以下は、DictionaryオブジェクトのItemに配列を格納する例です。
格納が済んでしまえば、
oDict("aryA") → 配列全体
oDict("aryA")(2,1) → "アボカド"
のように値を参照(取得のみ)できます。
aryA = oDict("aryA")
のようにすれば、配列aryAでは編集も可能になります。
Sub Re_c2() では、
一旦、基テーブルをExcel一般機能でソートしてからの処理になります。
ソースの並びが案外に不規則でしたので、元の並びに戻す為に、
事前にC列に昇順のIDを設定してからの実行になります。
(例:C2=1,C3=2,C4=3,...,C22=21)
Sub Re_j3() では、
ADODB.RecordsetのFilterプロパティで抽出結果としての配列を取得します。
先に挙げたSub Re_a1()はベタな総当たり判別でしたが、
「事前にソート」
または
「フィルターを用いる」
という過程を踏めば様々な方法で比較的簡単に書けるようになるかと思います。
Sub Re_j3()は外部オブジェクトを複数扱う分、記述は長めですが、
やってる内容は至ってシンプルなので、
仕様書も短文で済みますし、読む人にも理解され易く追加編集も容易、
という意味で、私の仕事でも実際に使っている手法です。
(xl2007以前では、使えなくもないですが問題あって薦められません)
要求も様々なら 方法も紹介し切れない程多彩 ですので、
お求めに適うものを提示できていないかもわかりませんけれど、
何かの参考にでもなれば幸いです。
設計の話抜きに配列の話を考えるのは、想定が拡がり過ぎて難しいので、
以後無理に答えを付けることもないかな、と思っていますので、ご理解を。
詳らかな補足や具体的な要求などもしあれば、またお応え出来るのかも、です。
-> 次の投稿へつづきます。