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

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

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

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

Q&A

解決済

2回答

3386閲覧

For文で一致条件したセル範囲を配列格納行う方法について

quark87139

総合スコア6

VBA

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

0グッド

0クリップ

投稿2021/12/03 09:17

編集2021/12/03 09:38

かなり初歩的な質問となってしまう可能性が高いかも知れませんが、
ネット上で検索してもそれらしき答えが出てこないためご質問させてください。

今回行いたい処理としては、
セル範囲(今回は1~54列の範囲)を変数に格納し、ループ処理で一致条件した分を
配列(Redim配列)に格納し、最終反映先(別シート)へ反映といった処理を行いたい。

1つずつの処理であれば、以下のようなイメージで上手くいくのですが・・・

vba

1tbl(i,1) = ms1.cells(i,1) 2tbl(i,2) = ms1.cells(i,2) 3tbl(i,3) = ms1.cells(i,3) 4.... 5tbl(i,54) = ms1.cells(i,54)

後先の修正やコーディングに時間が掛かることや処理時間が結構要していることから
セル範囲を変数に入れて代入すれば一括で格納できるのでは・・・と
考え、最終以下のようなコードで組み立てました。

VBA

1Sub 条件一致抽出反映() 2 3'---------------------------------------- 4Dim wb As Workbook 5Dim ms1 As Worksheet,ms2 as Worksheet 6 7Set wb = ThisWorkbook 8Set ms1 = wb.Sheets(1)'リスト 9Set ms2 = wb.Sheets(2)'反映先 10'---------------------------------------- 11 12mRow = ms1.Cells(Rows.Count, 1).End(xlUp).Row 13 14Dim tb, tbl 15Dim fnd1 As String, fnd2 As String 16Dim rng 17Dim i As Long, j As Long 18 19j = 1 20ReDim tbl(1 To mRow, 1 To 54) 21 22For i = 3 To mRow 23 24 fnd1 = ms1.Cells(i, 12).Value 25 fnd2 = ms1.Cells(i, 10).Value 26 rng = ms1.Range(ms1.Cells(i, 1), ms1.Cells(i, 54)).Value 27 28 If Not fnd1 = "対象外" Then 29 If fnd2 = "" Or fnd2 = "※" Then 30 tbl(j) = rng 31 j = j + 1 32 End If 33 End If 34Next i 35 36ms2.Range("A3:BB" & UBound(tbl)) = tbl 37 38End Sub

ところが「インデックスが有効範囲にありません。」と表示されて正常に動かない状況です。
そもそもセル範囲を配列に格納すること自体が間違っている可能性は高そうな気はしており、結局は行と列(x,y)を変数にしてFor文で回す他対応はなさそうな気はしています。

また自分なりにネット上で「VBA セル範囲 一致 格納」、「VBA セル範囲 ループ 格納」等
ヒットしそうなワードを組み合わせて検索したのですがそれらしきものが見当たらず、
解決に至っておりません。


イメージ図
イメージ説明


データ量:
A1からBB列最終行までの範囲から条件一致した分
※全体:最終行はおおよそ3万行を想定しているため、合計162万レコード程度


その他気になる点:
上手く伝わる自信はないのですが、
配列上の範囲(インデックス番号?)を別の配列に格納する方法はありますでしょうか。
イメージ:オブジェクト上で表した場合・・・Range(cells(i,1),cells(i,54))

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

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

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

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

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

guest

回答2

0

Excelの機能を使うというのではだめでしょうか。

vba

1Sub 条件一致抽出反映() 2 Dim wb As Workbook 3 Dim ms1 As Worksheet, ms2 As Worksheet 4 Dim mRow 5 6 Set wb = ThisWorkbook 7 Set ms1 = wb.Sheets(1) 'リスト 8 Set ms2 = wb.Sheets(2) '反映先 9 mRow = ms1.Cells(Rows.count, 1).End(xlUp).Row 10 11 Application.ScreenUpdating = False 12 With ms1.Range("A2:BB" & mRow) 13 .AutoFilter Field:=12, Criteria1:="<>対象外" 14 .AutoFilter Field:=10, Criteria1:="※", Operator:=xlOr, Criteria2:="" 15 .Copy ms2.Range("A2") 16 .AutoFilter 17 End With 18 Application.ScreenUpdating = True 19End Sub

投稿2021/12/03 11:54

hatena19

総合スコア33795

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

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

quark87139

2021/12/04 06:00

hatenaさん ありがとうございます! ご提示頂いたレコードを試行テストしてみたのですが、 正しい処理結果で尚且つ処理時間もそんなにかかりませんでした。ありがとうございます。 コード自体は理解できたのですが、 VBAは同じ計算結果を求めるには複数のやり方がある中でどのように使い分けているのか差し付けなければ教えて頂けないでしょうか。(当初の質問文から逸脱しておりすみません) オブジェクト か オブジェクトでないかの違いで使い分ける感覚ですかね? 私のVBAに対する認識度が低いためか・・・ データ量が多ければ多いほど配列を使った方が処理速度も速くなるという思い込みをしていました。
hatena19

2021/12/04 06:19 編集

Accessの機能でできることなら、そちらを使った方が高速な場合が多いです。 コードもシンプルになる場合が多いです。 抽出や並べ替えは、AutoFilterメソッド、Sortメソッドが高速です。 処理によってはVBAが高速な場合もあります。(FindメソッドやReplaceメソッドは遅いらしい) 速度を重視するなら、両方試してみて、速い方を採用すればいいでしょう。 VBAの場合は書き方によって速度差がでるのでそれも十分検討する必要があります。
quark87139

2021/12/05 09:18

大事なことを教わった気がします。本当にありがとうございます! ご指摘頂いた通り、単に決めつけるのではなくいくつかのやり方を採用・比較し、 使いやすさや処理速度が速いなど総合的に判断して採用するやり方でこれからも検討しながら 対応していきたいと思います。 ※どちらもベストアンサーにしたかったのですが、  今回は他の方の回答が早かったので気悪くされましたら申し訳ございません。
guest

0

ベストアンサー

こんな感じでどうでしょうか。(件数が多いとTransposeできないかも。)

VBA

1Sub 条件一致抽出反映() 2 3 '---------------------------------------- 4 Dim wb As Workbook 5 Dim ms1 As Worksheet, ms2 As Worksheet 6 Dim mRow 7 8 Set wb = ThisWorkbook 9 Set ms1 = wb.Sheets(1) 'リスト 10 Set ms2 = wb.Sheets(2) '反映先 11 '---------------------------------------- 12 13 mRow = ms1.Cells(Rows.Count, 1).End(xlUp).Row 14 15 Dim tb, tbl 16 Dim fnd1 As String, fnd2 As String 17 Dim rng 18 Dim i As Long, j As Long 19 20 j = 1 21 ReDim tbl(1 To mRow) ', 1 To 54) 22 23 For i = 3 To mRow 24 25 fnd1 = ms1.Cells(i, 12).Value 26 fnd2 = ms1.Cells(i, 10).Value 27 rng = ms1.Range(ms1.Cells(i, 1), ms1.Cells(i, 54)).Value 28 29 If Not fnd1 = "対象外" Then 30 If fnd2 = "" Or fnd2 = "※" Then 31 tbl(j) = rng 32 j = j + 1 33 End If 34 End If 35 Next i 36 37 ReDim Preserve tbl(1 To j - 1) 38 39 With WorksheetFunction 40 ms2.Range("A3:BB" & UBound(tbl) + 2).Value = .Transpose(.Transpose(tbl)) 41 End With 42 43End Sub

投稿2021/12/03 09:48

jinoji

総合スコア4585

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

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

quark87139

2021/12/04 05:45

Jinojiさんありがとうございます。 特にTranposeの部分において 私自身勉強不足の部分があり申し訳ないのですが以下ご教示頂けないでしょうか。 一部抜粋↓ rng = ms1.Range(ms1.Cells(i, 1), ms1.Cells(i, 54)).Value ① tbl(j) = rng ②.Transpose(.Transpose(tbl))  ①処理:オブジェクトで言い換えると1セルの中にセル範囲の情報を格納 ②処理:一次元配列から二次元配列に変換して一次元配列に変換? 上記の認識ですが相違ないでしょうか?②の処理がイマイチつかめていないです。。 また個人的には1つ(セル)ずつの処理を行う形であれば配列が適している印象ですが、 今回のような複数範囲を一括で処理を行うのは配列に向いていないんですかね?
jinoji

2021/12/04 06:37

②の処理はちょっと説明しづらいのですが、おおよそ以下の感じです。 WorksheetFunction.Transposeはもともと「セル範囲の行と列を入れ替えて貼り付け」的な機能で、 基本的には二次元配列に対して行うものなのですが、 今回のような「一次元配列の各要素が一次元配列になっているもの」にも何故か機能し、 しかも結果が二次元配列に変換されている、という仕様なので、 配列をセル範囲に書き戻すときにこれを利用する(行列が入れ替わるので二度掛けする)のが いにしえより伝わるExcelVBAの謎テクニックなのです。 一定の上限(おそらくその出自から列の最大数)を超える要素数には対応できないなどの制約があり、 使い方を誤るとハマりますが、うまく使うとハマります。
quark87139

2021/12/05 09:12

ご返信遅くなり申し訳ございません。 当初ご提示頂いたコードを拝見した際、Tranposeを続けて使ったら元に戻るのでは・・・と思っていたので分かりやすい説明頂いた理解できました。分かりやすい説明頂きありがとうございます。 また一定の上限を超えた場合、上手く作動しない場合もあるとのこと留意の上うまく使い分けてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問