質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

3回答

5503閲覧

2次元配列のインデックスが有効範囲にありません

退会済みユーザー

退会済みユーザー

総合スコア0

VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2021/06/07 01:20

編集2021/06/07 04:35

結論から申し上げます。

2次元配列にてExcelのデータを取得する際に、
1行目の取得が限界まで終了した後、
2行目の取得に移りたいと考えておりますが、
ここでエラーが出現する為、
別の方法で要件を満たすものを作りたいと考えております。
どなたかご教授下さい。
よろしくお願いします。

【エラー内容】
インデックスが有効範囲にありません
→場所:extractedData(j, i) = Cells(j + 4, i + 1)
において、右辺は正常に取得。しかし、左辺が参照できず。
エラー時のjとiの値
j=1,i=0
※ただし、iのFor文を回し終わった後の、jのFor文での2回目の処理での話です。
すなわち、
ある行で、取得したいデータがある右の最後の列まで取得後、次の行に移った時の話です。

【理解している事】
高次元配列において、最後の次元のみしか要素数を変更できない事。
すなわち、
ReDim Preserve buf(r, c)
において変更できるのはcのみ
Trancepose関数を利用しようにも、
以下のコードに加える事ができる方法がわかりかねております。

【実現したい事】
ある条件のもとで取得するデータを精査し、配列に入れて
新規シートにその精査後のデータを出力する。
※2次元配列にて、
Excelのデータ(A列~O列※ただしC列は取得しない)を取得
元データは縦が可変で横は不変。(縦=行、横=列)

・データを取得し配列に投下
・配列からデータを取り出し、新規シートへ出力する

現状は処理を2つにわけるプログラムを作っている最中です。

以下、現状のプログラムコード

※現在、データを取得してくる範囲はA4:O40です

VBA

1 2 3Dim CColum As String 4 5Dim lineNum As Integer 6 'COUNTA(A4:A40)=37と同等 7 lineNum = WorksheetFunction.CountA(Range("A4", Range("A" & Rows.Count))) 8 9 10'A列~O列まで 11ReDim extractedData(lineNum , 14) As Variant 12ReDim Preserve extractedData(lineNum, 14) As Variant 13 14For j = 0 To lineNum 15 16 For i = 0 To 14 17 'C列を無視(アルファベットが入っているデータがC列の為、以下で除外) 18 If Cells(j + 4, i + 1).Value Like "[A-Z]" Then 19 'C列を無視する為の捨て変数CColum 20 CColum = Cells(j + 1, i + 0) 21 Else 22 extractedData(j, i) = Cells(j + 4, i + 1) 23 End If 24 Next 25Next 26

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hatena19

2021/06/07 03:07

エラーがでるのはどの行ですか。 また、エラーがでたときに、その行のインデックスの値をデバッグで確認してみてください。 あと、説明では「C列は取得しない」となってますが、コードにはそのような処理はないようですが。
退会済みユーザー

退会済みユーザー

2021/06/07 03:12

修正しました。 ちなみに、デバッグなどの基本的な動作は既に試しています。 C列を無視という行が対象行です。条件文の中に正規表現を記載しております。hatena19さんにとって分かりにくいという事なので、かみ砕いた説明を追記しました
hatena19

2021/06/07 03:23 編集

C列を除くということなら If i<>2 Then extractedData(j, i) = Cells(j + 4, i + 1) End If でいいでしょう。 で、どの行でエラーがでて、そのときの j, i の値は何だったのでしょうか。
退会済みユーザー

退会済みユーザー

2021/06/07 03:26

文章を既に修正しましたので、ご確認下さい。 それとも、修正した文章がわかりにくいのか、文章を読んでいないのかどちらでしょうか。 (i = 0,j = 1)文章を読んで頂ければiがどの様な値でjがどの様な値かは理解して頂けるかと思いました。
hatena19

2021/06/07 03:35

extractedData(j, i) = Cells(j + 4, i + 1) の行でエラーが出て、そのとき i = 0,j = 1 ということでしょうか。 Option Base 1 というような宣言がありませんか。あるなら削除してください。 あるいは、下記のように開始値を省略せずに記述したらどうなりますか。 ReDim extractedData(0 to lineNum , 0 to 14) As Variant
退会済みユーザー

退会済みユーザー

2021/06/07 04:33

Option Base 1 という初期値の設定コードは記述しておりません。 開始値を 0 to lineNum , 0 to 14 と記述すると確かに目先のエラーは消失しました。 しかしながら、今度は全てのデータを取得できず、 22行分のデータが取得できませんでした。 Cell(1,19)=19行目~40行目までが取得できず。
guest

回答3

0

質問の内容とコードから、現状のやりたいことは A列からO列、4行目以降のデータがあるところまで、の範囲を配列に格納したい、ということだと推測。

だとしたら、ループしなくてもValueで取得可能。(hk3150さんが指摘済みです。)

vba

1 Dim lastLine As Integer 2 lastLine = Cells(Rows.Count, "A").End(xlUp).Row 3 4 Dim sourceData() As Variant 5 sourceData = Range("A4:O" & lastLine).Value

この配列に対して内容を精査して別配列に出力すればいいでしょう。
具体的な処理は不明なのでとりあえずDebug.Print で出力する例。

vba

1 Dim r As Long, c As Long 2 For r = 1 To UBound(SourceData) 3 For c = 1 To UBound(SourceData, 2) 4 'C列はとばす 5 If c <> 3 Then 6 Debug.Print SourceData(r, c) 7 End If 8 Next 9 Next

投稿2021/06/07 04:40

編集2021/06/07 05:40
hatena19

総合スコア34075

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/06/07 05:16

実現したい事は仰る通りですが、 なぜ2次元配列の手法を用いるかの目的を申し上げます。 後に以下の処理を行う目的がある為です。 A列のデータとB列のデータで重複しているデータは削除し出力 重複していなければそのまま出力 D列のデータで、AA列で重複しているデータをもとに、D列のデータを合算し出力 (合算前データは合算後削除) 例100+150=250 この250を残して100と150は出力するデータにはのせない。 重複していなければそのまま出力 これを1次元配列で行うと、 列の数だけコーディングしなければならず、 冗長で保守性がないように思えます 例:A列B列を取得して出力 A列D列を取得して出力 A列E列… その為に多次元配列を使う事にしました。 ご回答頂きました内容の Range("A4:B" & lastLine) これはA列とB列のみの選択に思えます。 上記意図に反する気がします。 格納データについて A列とB列 →文字列データ  重複しているデータもあるが、重複していないデータもある D列~O列 →数値データ  重複しているデータもあるが、重複していないデータもある
hatena19

2021/06/07 05:39

> Range("A4:B" & lastLine) > これはA列とB列のみの選択に思えます。 > 上記意図に反する気がします。 これは、Range("A4:O" & lastLine) に変更すればいいでしょう。回答を修正しておきます。 > A列のデータとB列のデータで重複しているデータは削除し出力 > 重複していなければそのまま出力 > D列のデータで、AA列で重複しているデータをもとに、D列のデータを合算し出力 重複をチェックするなら、VBAの場合は、Dictionary(連想配列)を使うのがいいでしょう。 検索すればサンプルコードはいろいろ見つかります。 これで対象セル範囲を二次元配列を取得できるのでそれをデータ精査しながら、出力用配列に入力していけばいいでしょう。
退会済みユーザー

退会済みユーザー

2021/06/08 00:39

ご指摘ありがとうございます。 とても参考になりました。
guest

0

ベストアンサー

VBA

1Sub Sample() 2 3 Dim lineNum As Integer 4 lineNum = WorksheetFunction.CountA(Range("A4", Range("A" & Rows.Count))) 5 6 ReDim extractedData(1 To lineNum, 1 To 14) As Variant 7 8 Dim i, j, c 9 For j = 1 To lineNum 10 c = 1 11 For i = 1 To 15 'A列~O列まで 12 If i <> 3 Then 'C列以外 13 extractedData(j, c) = Cells(j + 3, i) 14 c = c + 1 15 End If 16 Next 17 Next 18End Sub

投稿2021/06/07 04:17

jinoji

総合スコア4592

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/06/07 04:47 編集

上記コードで試験的に運用してみた結果、 全てのデータを取得できませんでした。 具体体にどのデータが取得できなかったかと申し上げますと、 22行分のデータが取得できませんでした。 A19:P40=19行目~40行目までのデータが存在する範囲が取得できず。 許容上限が存在するのでしょうか。
jinoji

2021/06/07 04:53

処理対象の範囲で、A列が空白の行がありますか?
退会済みユーザー

退会済みユーザー

2021/06/07 04:55

いえ、空白の行はございません。 A4~A40において、データは全て入っております。
jinoji

2021/06/07 04:58

ということは lineNum は 37ですか?
jinoji

2021/06/07 05:00

全てのデータを取得できませんでした、というのは、どうやって確認したのですか?
jinoji

2021/06/07 05:09

試しに、 Worksheets.Add.Cells.Resize(UBound(extractedData, 1), UBound(extractedData, 2)).Value = extractedData を最終行に入れて実行してみてください。 37行15列のデータで、 22行分の、といっているので (37-15=22であることから、)行と列の数字をどこかで取り違えているんだろうなあと想像します。
退会済みユーザー

退会済みユーザー

2021/06/07 05:36 編集

確かに lineNum =37 です。 確かにそちらのコードですともれなくでました。 以下で確かめました。 For文を用いている意図は、 ここから更に A列のデータとB列のデータで重複しているデータは削除し出力 重複していなければそのまま出力 D列のデータで、A列で重複しているデータをもとに、D列のデータを合算し出力 (合算前データは合算後削除) 例100+150=250 この250を残して100と150は出力するデータにはのせない。 重複していなければそのまま出力 という事を実現する為に一つ一つのデータに 条件分岐をあとで付け加える為でございます。 '新規シートを名前を変更してシートの最後尾に挿入 Dim NewWorkSheet As Worksheet Set NewWorkSheet = Worksheets.Add(After:=Worksheets(Worksheets.Count)) NewWorkSheet.Name = "Sheet2" 'リストを出力 For j = 1 To lineNum For i = 1 To 15 NewWorkSheet.Cells(j + 3, i).Value = extractedData(i, j) Next Next
jinoji

2021/06/07 06:22

行と列の数字をどこかで取り違えているんだろうなあという想像が当たっていたようです。 extractedData(i, j) となっている箇所は extractedData(j, i) が正しいはずです。
退会済みユーザー

退会済みユーザー

2021/06/07 06:52

ありがとうございます。 単純に extractedData(j, i) とした時に一行目までしか出力されなかったので、 特に解析せずに(i, j)と目先の結果を早く出す、 という暴挙に出たのがいけなかったようです。 実際は出力先にはC列が除外されているので、 その数だけ最終値をマイナス1してTo 14としなければならなかったです。 教えて頂きありがとうございます。 今後の開発に役立てたいので、 ぜひ教えて頂きたい事があります。 For文の中に c=1 と3つ目の変数を用いる手法は大変感動しました。 この手法はどの様な思考から出てきたのか教えて頂きたいです。 例えば、繰り返し処理のモデルケースの一つ、 や何かの考えから引用した、 またはこういうロジカルな考え方で導き出した、 などぜひ教えて頂きたいです。
jinoji

2021/06/07 07:05

思考だのなんだのとそんなカッコいいものはなく、 単に「C列を無視なんて面倒くさい条件があるから i で兼用できない、だったら別の変数使うしかないか」と思っただけです。 もう少し広い視野で考えると、ここで作った二次元配列を出力するときには単純に一発貼り付けでなくて合算などのロジックがあるとのことなので、だったら二次元配列に格納するときにはC列をわざわざ無視するのではなく単純に作ってしまって、出力の時にうまいこと除外することを考えたほうが全体としてはシンプルなのかもなあ、とは思いました。
guest

0

こんにちは。

少し長くなりますが、下記のように一度、配列に入れてしまってから、
Dim MyArray
MyArray = Range("A1:B100").Value

その配列内から必要なものだけを別の配列に格納されてはどうでしょう。(forやdoを用いて)

一度配列に入れてしまえば、
各次元の要素数はuboundで分かるでしょうから、変化にも対応しやすいのではないでしょうか。

ちなみに、変数numはどのように定義されているのでしょうか。。
ReDim extractedData(num , 14) As Variant

投稿2021/06/07 03:17

hk3150

総合スコア11

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/06/07 03:23

>各次元の要素数はuboundで分かるでしょうから、変化にも対応しやすいのではないでしょうか。 この説明が抽象的で私にはわかりかねております。 つまり、どういうことでしょうか。 >ちなみに、変数numはどのように定義されているのでしょうか。 誤っておりましたので修正いたしました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問