• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:Excel2003VBA Variantについて)

Excel2003VBA Variantについての質問とエラーの原因

このQ&Aのポイント
  • Excel2003VBAのVariantについての質問です。
  • エラーが発生している部分はyのコードで、インデックスが有効範囲外というエラーが表示されます。
  • 原因として、yのコードではBの配列をA1からA10の行数にResizeしているため、15要素にResizeするとエラーが発生します。

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

  • ベストアンサー
  • nicotinism
  • ベストアンサー率70% (1019/1452)
回答No.1

大丈夫な気がして試すと確かにエラーに ローカルウィンドウを出しながらステップ実行したらわかりました Sub y() Dim B As Variant     ReDim B(1) '・・・(1)・・・・・・・・A     ReDim B(5) '・・・(2)・・・・・・・・B     B = Evaluate("row(A1:A10)") '・・・・C     ReDim Preserve B(15) '・・・(3) ・・D End Sub Aを通った直後に、B の型は Variant/Variant(0 to 1) Bでは、Variant/Variant(0 to 5) Cでは、Variant/Variant(1 to 10,1 to 1) ←これが問題の引き金 になります。 DでRedim Preserve しようとするとエラーになるのはヘルプに載ってます。 以下抜粋 キーワード Preserve を指定した場合、変更できるのは、動的配列の最後の次元のサイズに限られます。 また、次元数は変更できません。 たとえば、次元が 1 つしかない動的配列の場合、その次元は最後のただ 1 つの次元なので、 その次元のサイズを変更できます。 次元が 2 つ以上ある動的配列の場合、 最後の次元のサイズのみを変更でき、その配列に格納されている値は保持されます。 ただし、ほかの次元の大きさは変更できません。 --ここまで ReDim Preserve B(15) は、0~15の一次元の範囲を設定することになりますが 上記ヘルプの1~2行目に引っかかります。 で、なんで二次元配列に、Evaluate("row(A1:A10)") でなるかというと・・・ 推測にすぎませんが、内部的には、RowとColumn関数を一緒に扱っていて 「だったら二次元配列でいいんじゃない?とMS社の人は考えた」となっているのかな?と思います。

Nouble
質問者

お礼

有り難うございます。 なるほど! 配列の構造が違うのですね 迂闊でした。 助かりました。

その他の回答 (4)

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.5

#2、3、cjです。 訂正が2件あります。 例示の記述にミスがありました。正しくは   Dim B   ReDim B(1 To ub)   B(1) B(2) B(3) B(4) ... B(ub)   ReDim Preserve B(ub)    ↓   ↓   ↓   ↓     ↓   B(0) B(1) B(2) B(3) ... B(ub - 1) B(ub) = Empty でした。 Re8111406mtxのコメントが間違っていました。正しくは   B = Evaluate("row(A1:A" & nRowsCn & ")")  '  B(1 To nRowsCn, 1 To 1)   B = Application.Transpose(B)  '  B(1 To nRowsCn)   ReDim Preserve B(1 To 15)  '  B(1 To 15)   B = Application.Transpose(B)  '  B(1 To 15, 1 To 1) でした。 以上訂正お願いします。       /// Re: あ、いえ、わざわざ、すみません。 こちらこそ、ずっと以前から勉強になることばかりですから、、、。 また参考にさせて頂くことも多いと思いますので 変わらずご活躍くださいませ。よろしくお願いします。     cj

Nouble
質問者

お礼

了解致しました、訂正有り難うございます。

  • nicotinism
  • ベストアンサー率70% (1019/1452)
回答No.4

なるほど~^10 AccessにEval関数てのがありまして、 ExcelのEvaluate も似たようなモンと思い込みしてました。。。 あらためてヘルプを読んでます。 非常にスッキリしました。ありがとうございます。

Nouble
質問者

お礼

私のような者の発言がお役に立てたご様子、 光栄に思います。

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.3

> 例外的に > Evaluate("ROW(A1)") > これ↑が何故か一次元で返ってしまうのは、私にも説明できませんが、 あー、これ、 結果的に二次元配列を返すけれど、過程ではジャグ配列、 という例の説明でいいみたいですね。 この点は私よりもNouble さんの方がお詳しいことと存じます。 // でも、二次元で(統一して)返してもらった方が親切ですよねー。

Nouble
質問者

お礼

恐縮の余り入れそうな穴を探してしまいます 滝汗 >でも、二次元で(統一して)返してもらった方が親切ですよねー。 そう私も思います。

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.2

こんにちは。お邪魔します。 #1さんのご回答で解決に必要な情報は得られていると思います。 私は応用の部分で参考になりそうなことを書いてみます。 注意点として Excel.SpreadSheetと配列変数の受け渡しをする時は Excelから返される配列が必ず 1オリジン だということに注意してください。 ReDim Preserve での Dimension指定は必ず (1 To ub1, 1 To ub2) または (1 To ub) のようににします。 ここを間違えて、 (ub1, ub2) または (ub) のように書いてしまうと   Dim B(1 To ub)   B(1) B(2) B(3) B(4) ... B(ub)   ReDim Preserve B(ub)    ↓   ↓   ↓   ↓     ↓   B(0) B(1) B(2) B(3) ... B(ub - 1) B(ub) = Empty のように添え字がずれてしまって思わぬ結果になりかねません。 (意図的にそういう使い方をする場合もあるにはあるのですけれど、、、) また、配列のサイズもメモリのサイズもずれてしまいますので。 Option Base 1 とモジュール単位で指定してあれば別ですが、 その場合は、0オリジンで扱われる筈の他の配列変数がある場合に 逆の意味での注意が必要ということになります。 或いはもしかして、質問文に Option Base 1 と書き忘れた、という話でしたら、 それを小さなミスと考えないほうがよいです。 配列の扱いは、とにもかくにも、Explicit を心掛ける必要がある、という意味です。 Evaluate メソッドの親オブジェクトを省略する場合、 且、引数の文字列式にシートを指定しない場合は、 親オブジェクトを意識して書くようにしましょう。 例えば、Sheet1 モジュールの記述として   Debug.Print Application.Evaluate("b2")   Debug.Print Evaluate("b2") 前者はアクティブシート 後者はSheet1 が、それぞれの親オブジェクトです。   Debug.Print Me.Evaluate("b2") の省略形なのか   Debug.Print Application.Evaluate("b2") の省略形なのか で結果が違ってくる場合もありますので。 Evaluate メソッドで評価を期待する文字列式のうち、 ワークシート関数を指定した場合では、 ROW() COLUMN() のように Optionalな引数としてセル範囲を指定できる関数 については、引数を指定した時点で(Evaluate数式では指定が必要なのですが)、 FormulaArray(複数のセル範囲で数式を適用した配列数式)扱いになりますから、 戻り値はスカラーではなく、原則、二次元配列になります。 例外的に Evaluate("ROW(A1)") これ↑が何故か一次元で返ってしまうのは、私にも説明できませんが、 Excel.SpreadSheetと配列変数の受け渡しについては、 単一セルの扱いだけは特別な注意が必要ということは、 これに限った話ではありませんので、形で覚える他ないのかな、と。 参考)   Dim B   nRowsCn = Cells(Rows.Count, 1).End(xlUp).Row  '  1   B = Cells(1).Resize(nRowsCn).Value   → nRowsCn が 1 だった場合だけ、B は二次元配列ではなくスカラー。とか。       ご提示のコードで意図したように配列をリサイズする方法を2例。 Re8111406arr: Evaluateの文字列式によって一次元配列へ置換しておいて リサイズ→行列置換 Re8111406mtx: Evaluateはそのまま二次元を返すようにして 行列置換→リサイズ→行列置換  XSize は変更できても YSize は変更できない、ならば、  XとYを行列置換してからリサイズしてしまおう、というようなお話。 2例とも実用コードとしてインプット、アウトプットがある形で書いています。 今回は行列置換の方法を解り易くする為に Application.Transpose や "TRANSPOSE()" を用いて書いていますが 配列のコンバートは、前にもお話したように、普通にループした方が有利です。 ' ' ================================================================= Sub Re8111406arr()   Dim nRowsCn As Long   Dim B As Variant   Dim i As Long   nRowsCn = 10 ' Cells(Rows.Count, 1).End(xlUp).Row   B = Evaluate("transpose(row(A1:A" & nRowsCn & "))")  '  B(1 To nRowsCn)   ReDim Preserve B(1 To 15)  ''  B(1 To nRowsCn)   B = Application.Transpose(B)  '  B(1 To 15, 1 To 1)   For i = nRowsCn + 1 To 15     B(i, 1) = i   Next i   With Cells(5).Resize(15)     .Value = Empty     .Value = B   End With End Sub Sub Re8111406mtx()   Dim B As Variant   Dim nRowsCn As Long   Dim i As Long   nRowsCn = 10 ' Cells(Rows.Count, 1).End(xlUp).Row   B = Evaluate("row(A1:A" & nRowsCn & ")")  '  B(1 To nRowsCn, 1 To 1)   B = Application.Transpose(B)  '  B(1 To 15)   ReDim Preserve B(1 To 15)  '  B(1 To 15)   B = Application.Transpose(B)  '  B(1 To 15, 1 To 1)   For i = nRowsCn + 1 To 15     B(i, 1) = i   Next i   With Cells(5).Resize(15)     .Value = Empty     .Value = B   End With End Sub ' ' ================================================================= 以上です。

Nouble
質問者

お礼

何時もご教示を有り難うございます。 今回も >FormulaArray扱いになりますから、 戻り値は原則、二次元配列になる の下りや transposeによる1次元化など 私では到底おぼつかない内容… とても楽しく拝見しました。 またバカなことばかりお伺いするとは思いますが、 今後ともどうぞ宜しくお願い致します。

関連するQ&A