- ベストアンサー
2次元配列について、教えてください。
基本的なことなのでしょうがまだよくわかっていません。 ワークシートにたとえると、1次元は縦方向(行番号方向)、二次元は横方向(列番号方向)ですよね? 列数、行数にあたるのが1次元、二次元それぞれの添字ですよね? そしてセルに当たるのが「要素」ですよね? 以上の解釈があっていたら、 1.A列やB列にあたるものはなんと呼ぶのでしょうか? 2.1行目や2行目にあたるのはなんと呼びますか? 3.ワークシートで行や列を削除するような感じで2次元配列の行や列にあたるものを削除することはできますか? 4.UBound関数は、配列の大きさを調べられますが、この大きさは添字です。ワークシートのCells(65536,1).End(xlUp)Rowのように実際にデータがどこまで入っているか調べられますか? 教えてください。 前提とした解釈自体が違っていたらそれもご指摘ください。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
#8の回答者です。 コードは基本的な間違いがありましたので、修正しました。 もう一度、見ていただけますか?MaikingMatrix等で、少なくとも10行×8列以上の行列を出しておいてから、試してみてください。 '// Sub Test1R() '配列を抜き出す修正版 Dim ar, x, y, i, j Dim ar1 Dim ary ar = Range("A1").CurrentRegion ReDim arx(1 To UBound(ar, 1)) '行 j = 1 For i = 1 To UBound(ar, 1) If i <> 5 Then '5行目を省く arx(j) = i j = j + 1 End If Next ReDim ary(2, 0) '列抜き出し ary(0, 0) = 1 ary(1, 0) = 3 ary(2, 0) = 5 ar1 = Application.Index(ar, arx, ary) ar1 = Application.Transpose(ar1) x = UBound(ar1, 1) y = UBound(ar1, 2) Range("A15").CurrentRegion.ClearContents Range("A15").Resize(x - 1, y).Value = ar1 End Sub >なぜar1に配列arのデータがループしてないのに入るのかも理解できませんでした。 なぜかというのはブラックボックス化して分かりませんが、これは、古いExcelのVer.4 のマクロの名残りのテクニックです。マクロ関数が配列を排出しますので、それと同時に使われた関数を、利用出来るのではないかと、私が考えました。今では、TRANSPOSEなどの新しい関数が頻繁に用いられますが、古くからあるINDEX関数の他にも、COLUMNS、ROWS関数というものが、使われることがあります。 他には、VBA関数のFilter 関数、Join関数、Split関数などが扱われます。これらは、2次元配列は用いられません、1次元配列のみです。上手に、ワークシート関数を用いれば、便利なツールになるものだと思います。 ところで、話は戻りますが、VBAの配列を再確認するために、ここにご質問になったのですよね。こうした些末な情報は、返って混乱にはなるかとは思いましたが、配列は、私にとって研究課題です。 実際に、仕事の時のプログラミングでコードを書くときは、こういうテクニックを頻繁に使うことはハバカられますが、試しで使うには良いことだと思います。実務上では、意外に正攻法なコードしか書かないものです。二次元の動的配列まで使えれば、配列は卒業です。その後を研究している人はあまりいませんが、仮に、ワークシート関数が使えるとか、使えないかとかいう話は、裏技にしか過ぎません。しかし、今後将来、再び、このテクニックは出会うことになります。 4は、Small関数を使って、並べ替えしていますが、5は、.Net を使った並べ替えの技術です。 '// Sub Test4() '並べ替え Dim ar, arx(1 To 10) ar = Range("A1:A10").Value ar = Application.Transpose(ar) For i = 1 To 10: arx(i) = i: Next i ar = Application.Small(ar, arx) Range("A15").Resize(10, 1) = Application.Transpose(ar) End Sub Sub Test5() '並べ替え Dim AL As Object Dim i As Long Set AL = CreateObject("System.Collections.ArrayList") For i = 1 To 10 AL.Add Cells(i, 1).Value Next i AL.Sort Range("A15").Resize(10, 1) = Application.Transpose(AL.ToArray) End Sub
その他の回答 (8)
- Wendy02
- ベストアンサー率57% (3570/6232)
私も、少し、書かせていただきます。 前回の話の続きというか、私の前回のコードの説明になりますが、一部の方と回答とは違います。 1,2 >ワークシートにたとえると、1次元は縦方向(行番号方向)…… 行列(Matrix)というのは、言葉どおり「行」と「列」ですが、概念として逆だったと思います。 配列を、[For Each in 配列]で、ループすると、縦に進んでいきます。行は、縦(Vertical)、列は、横(Horizontal)です。数学の概念を持ち込むとややこしいので、VBAでは、一般的には、1次側、2次側と読んでいることが多いです。 ただ、Excelの場合は、ワークシートから取ると、ジャグ配列という、特殊な配列構造になってしまいます。あまり、気にする必要はありません。 >3.ワークシートで行や列を削除するような感じで2次元配列の行や列に…… ExcelとVBAでは厳密には違ってきますが、ふつうは、ループして、もうひとつ別の配列に入れて上げます。下を切るのは、Redim Preserve で可能です。Index 関数を使って切り出すことも可能です。 Sub MakingMatrix() '行列を作る Dim r Set r = Range("A1").Resize(10, 8) With r r.Formula = "=RANDBETWEEN(1,99)" r.Value = r.Value End With End Sub '--------- Sub Test1() Dim ar, x, y Dim ar1 Dim ary ar = Range("A1").CurrentRegion ReDim arx(1 To UBound(ar, 1)) '行 For i = 1 To UBound(ar, 1) If i <> 5 Then '5行目を省く arx(i) = i End If Next ReDim ary(2, 0) '列抜き出し ary(0, 0) = 1 ary(1, 0) = 3 ary(2, 0) = 5 ar1 = Application.Index(ar, arx, ary) ar1 = Application.Transpose(ar1) x = UBound(ar1, 1) y = UBound(ar1, 2) Range("A15").CurrentRegion.ClearContents Range("A15").Resize(x, y).Value = ar1 End Sub 行を、ひとつ(5行目)を抜き、列(1,3,5)を抜き出す >4.UBound関数は、配列の大きさを調べられますが、……実際にデータがどこまで入っているか調べられますか? Sub Test3() Dim ar As Variant, x, y ar = Range("A1").CurrentRegion x = UBound(ar, 1) y = UBound(ar, 2) End Sub 2次元配列では、空のデータとの区別は付きません。 >COUNTA関数のようなものでデータ数をひろうなんてことも不可。 そういうことではなくて、2次元配列だから、ダメのなのです。 一旦、1次元配列に変換しないと分かりません Transpose 関数や、Index 関数で、1次元配列を抜き取ります。 配列を扱えるワークシート関数なら、扱うことは出来ます。例えばMatcht関数などは良く用いられます。 Dim ar, ret ar = Range("A1:A100").Value ar = Application.Index(ar, 0, 1) ar = Application.Transpose(ar) ret = Application.Match(10 ^ 10, ar, 1) '最終行を探す Test1 の場合、 ar2 = Application.Index(ar1, 0, 1) ar2 = Application.Transpose(ar2) j = Application.CountA(ar2) 最後の行を切りだして、そして、その列を調べるということをしますが、通常、ループしながら調べる方法を取ります。
お礼
ご丁寧にありがとうございます。 > 配列を、[For Each in 配列]で、ループすると、縦に進んでいきます。 知りませんでした。 Sub 進行方向確認() Dim V, a V = Range("A1:C3").Value For Each a In V MsgBox a Next End Sub としたらそのとおりでした。 > 行を、ひとつ(5行目)を抜き、列(1,3,5)を抜き出す Sub Test1()をそのまま実行したところ、列(1,3,5)は抜き出されましたが、5行目は1行目のデータに入れ替わったみたいで行数には変更がありませんでした。 ar1 = Application.Index(ar, arx, ary) でなぜar1に配列arのデータがループしてないのに入るのかも理解できませんでした。 ありがとうございます。
- m_and_dmp
- ベストアンサー率54% (987/1817)
すみません、間違えました。あれでは、横配列になります。 コードの6行目を訂正しました。 Sub 一次元配列TEST() Dim tmp As Variant tmp = Split("A,B,C,D", ",") i = 0 Do While i < 4 Cells(i + 1, 1) = tmp(i) i = i + 1 Loop 'Range("A1:D1").Value = tmp '正しく転記 'Range("A1:A4").Value = tmp 'Aのみ4つ転記 End Sub
お礼
ありがとうございました。
- m_and_dmp
- ベストアンサー率54% (987/1817)
4個の要素で構成されるデータがあるとしまして、エクセルシート上に、A1,B1,C1,D1に配置してもA1,A2,A3,A4,に配置しても一次元です。 4個の要素を、 A1,B1 A2,B2 に配置するなら二次元配列です。 VBA上で、区切りのある文字列をSplit関数で処理すると、複数の要素を持つ一次元配列になります。このとき、VBA上では数学的仮想空間なので、縦(行)方向とか、横(列)方向とかの性質はありません。 貴殿は、シート上で縦方向に配列するのが一次元、横方向に配列するのが二次元と理解されていますので、Splitの戻り値が一次元配列になるのだから、ワークシート上で縦に配列すると、正しく分離された要素が表示されると考えていらっしゃることが分かりました。(質問の意味が分かりました。) しかし、先にも述べたとおり、VBA上では縦横の性質を持ちませんので、配列をシート上に投影したとき縦にするか横にするかはVBAのコードで決めるしかありません。 貴ご呈示のサンプルを次のようにしてみました。 Sub 一次元配列TEST() Dim tmp As Variant tmp = Split("A,B,C,D", ",") i = 0 Do While i < 4 Cells(1, i + 1) = tmp(i) i = i + 1 Loop 'Range("A1:D1").Value = tmp '正しく転記 'Range("A1:A4").Value = tmp 'Aのみ4つ転記 End Sub
お礼
そうでしたか。 一次元はあくまで長さという概念だから縦横は存在しないってことですね。 ありがとうございます。
- MRT1452
- ベストアンサー率42% (1391/3293)
> 1.2は配列でもやはり行や列でOkなんですね。 まぁ、そう認識しても問題ない。と言ったところかと。 人によってはX,Yとか言う人もいますし。 認識上、2次元配列は行列としてみても構わないという感じかな。 原則は質問4以降に書いたものなので。厳密には、行とか列とかいう固定的な呼び方は無いです。 おおよそ適正ではないかと思う呼び方であれば、「第○次元目の配列」という感じになるかと。 > 3.はその行を削除するのではなく中の要素を消去するだけで、下の行を繰り上げることはできないということでしょうか? その認識で良いです。 配列で、消した部分を詰めるなら、その処理を記述する必要があります。 > 4は不可ということですね? そうです。 UBound関数で要素数を取って、その跡にループ処理で、中身をチェックするという方法を取る必要があります。
お礼
丁寧に説明していただきよくわかりました。 2次元配列はワークシートに似てるけど、あくまで別物。 COUNTA関数のようなものでデータ数をひろうなんてことも不可。 やるなら全部の要素をループしてカウントする必要があるってことですね。 ありがとうございます。
- m_and_dmp
- ベストアンサー率54% (987/1817)
一次元は「線」、二次元は「面」、三次元は、「立体」と考えたらいいと思います。 三次元はエクセルシート上では展開しにくいので、二次元までとし、二次元はセルを横(列)方向にいくつか、縦(行)方向にいくつかとった、領域になります。 一次元は横または縦方向にいくつかとった領域になります。 VBAの場合は、シート上ではなく、数学的な仮想空間なので自由に三次元でも四次元でも考えることができます。 一つの要素からなる変数の例: hennsuu 一次元の変数の例: hennsuu(i) 二次元の変数の例: hennsuu(i,j) VBAではシートという制限がないので三次元も: hennsuu(i,j,k) 一次元の変数の要素は i 個あります。hennsuu(1), hennsuu(2), hennsuu(3) ..... 二次元の変数の要素は i x j 個あります。
お礼
わかりやすい説明をありがとうございます。 それで二次元配列の場合、1次元は縦方向、二次元は横方向ですよね? ところが Sub 一次元配列TEST() Dim tmp tmp = Split("A,B,C,D", ",") Range("A1:D1").Value = tmp '正しく転記 Range("A1:A4").Value = tmp 'Aのみ4つ転記 End Sub のように一次元配列をワークシートにそのまま転記すると2次元方向にしないといけないのが不思議です。 1次元方向にうるにはTranspose関数が必要になってしまいます。
- layy
- ベストアンサー率23% (292/1222)
エクセルで?、数学的?、プログラミング定義で?、 それぞれ調べると良いのでは?。 列、行、セル、X軸、Y軸、ベクトル、添え字、インデックス、・・・・等。 列=カラム(column)、綴りは間違えやすいです。 縦方向=row 横方向=column プログラムなどで、 xxケタ目を「xxカラム目」と言うことあります。 3の意味がわかりませんが、 どの言語だったか、 配列(3,4)をいったん配列(1,1)にして 配列(3,4)にし初期化を試みるようなことはありました。
お礼
ありがとうございます。 3の意味は、二次元配列でそのrowを削除して、下のrowを繰り上げることはできないかということです。
補足
> エクセルで?、数学的?、プログラミング定義で?、 ワークシートと書いたのですからエクセルのことです。
- MRT1452
- ベストアンサー率42% (1391/3293)
1 列(Row)です。 2 行(Calumn)です。 3 消すというよりはNULLにするという感じになるかと。 原則として、VBAでの変数は一度宣言すると、データの有無に関係なく、その領域を固定で確保します。 Redimによって配列数等の宣言しなおし等かのですが、これにも制約があり、シートのようには扱えない場合があります。 4 UBound関数は対象次元の配列の大きさを取得するだけなので、 中のデータがどこまで入っているかというのは、それだけでは調べられないでしょう。 基本的にシートと2次元配列は別個のものです。 ただ、考え方として、行列にすると判りやすいので、 参考書等では2次元配列は、行列の形で説明されている場合が多いというだけです。 配列変数はあくまで「配列」であって「行列」ではないので。 そのため、シート関連の命令と同じようなことをするには、ループや判定等でプログラムを組んでやる必要があります。 また、変数は構造体という概念もあるのでそういったものを活用します。 シート関連ははあくまでブック、シート、セルでしか扱うことは出来ません。
お礼
ありがとうございました。 1.2は配列でもやはり行や列でOkなんですね。 3.はその行を削除するのではなく中の要素を消去するだけで、下の行を繰り上げることはできないということでしょうか? 4は不可ということですね?
- layy
- ベストアンサー率23% (292/1222)
A1やA2やA3の1や2や3が添え字です。 配列とは? 何かをネットや用語辞書で探して見ましょう。
お礼
ありがとうございます。 でもそんなこと聞いてません。
お礼
> VBAの配列を再確認するために、ここにご質問になったのですよね。 そうです。 なんどもありがとうございました。 ちょっと私にはまだ高度すぎたようです。