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

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

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

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

Q&A

解決済

3回答

398閲覧

VBAでシートの情報を自動で配列化したい

nstto12

総合スコア18

VBA

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

0グッド

0クリップ

投稿2019/03/08 12:03

前提・実現したいこと

エクセルファイルをVBAで操作したい

<前提>
①:対象のエクセルのシート数・データ数は都度変わる
②:エクセルのA3からH(n)までの情報を取得し、配列化したい

発生している問題

配列は作れたものの、各シートの情報を格納したものではなく、 対象のブックが開かれたときにアクティブになるシートの情報しか得られません。 例として、シート1は範囲がA3~H99までとしたとき、範囲が(97,8)となる配列は作れるものの、 配列の中身がシート3だったり4だったりしています。 初心者なのできっとしょうもない過ちを犯しているのでしょうが、 調べてみても解決策は見出せませんでした。

該当のソースコード

Sub testMain() Dim fName As String 'ファイルネーム Dim wb As Workbook 'ワークブックオブジェクト Dim sCount As Integer 'シート数 MsgBox "操作したいファイルは予め保存の上閉じてください" ' ファイルを開くダイアログ表示 fName = Application.GetOpenFilename(",*.xlsx") ' ワークブックを開く Set wb = Workbooks.Open(fName) '対象のワークブックのワークシート数を取得する sCount = wb.Worksheets.Count '取得したシート数分処理を繰り返す Dim i As Integer For i = 1 To sCount 'ループの中でSubを実行 Call testSub(i, wb) Next i MsgBox "完了しました" End Sub ■■■■■■ Private Sub testSub(i, wb) Dim rCount As Long '行数 'iシート目のワークシートオブジェクトの行数を取得する rCount = wb.Worksheets(i).Cells(Rows.Count, 1).End(xlUp).Row '配列を用意 Dim arr() As Variant With wb.Worksheets(i) 'arr(rCount-2,8)の配列を作る arr = Range("A3:H" & rCount) End With 'MsgBoxで試しに出力してみたところ、範囲はiシート目のものだが、中身の情報が全て特定の1シートになっている。 MsgBox arr(rCount - 2, 3)    End Sub

試したこと

範囲を配列に代入する際、
arr = wb.Worksheets(i).Range("A3:H" & rCount)
とした所”型が一致しません”のエラーが出てしまいます。

補足情報

前提で書いた処理が面倒でVBAに手を出した初心者なので、
試したことの情報が少なく恐縮です。
上のコードもまだ完成形ではなく、最終的には配列内の要素同士を比較し、
結果を別配列に格納する下記のような処理を自動で行うマクロが作りたいです。
If arr(i,2)<>arr(i-1,2) Then
arrA(i) = 0
End If

wb.Worksheets(i).Range("B" & i ).Value<>wb.Worksheets(i).Range("B" & i-1).Value
のように直接比較するコードは書けたのですが、同様の処理を1行内で数個所行い、
更にi=rCountとなるまで繰り返す必要があるので、1シートの処理に数分かかる有様でとても使い物になりません。
皆様の知恵をお借りしたく投稿いたしました。知恵をお貸しください。

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

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

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

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

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

guest

回答3

0

アクティブなシートしか対象にならない原因は、nmoaさんの回答どおりだと思います。

testSub の引数を i(インデックス), wb(WorkBook) とせずに、
対象のWorkSheetにすればシンプルになります。

vba

1Sub testMain() 2 Dim fName As String 'ファイルネーム 3 Dim wb As Workbook 'ワークブックオブジェクト 4 Dim sCount As Integer 'シート数 5 6 MsgBox "操作したいファイルは予め保存の上閉じてください" 7 8 ' ファイルを開くダイアログ表示 9 fName = Application.GetOpenFilename(",*.xlsx") 10 ' ワークブックを開く 11 Set wb = Workbooks.Open(fName) 12 13 Dim ws As WorkSheet 14 For Each ws In wb.Worksheets 15 'ループの中でSubを実行 16 Call testSub(ws) 17 Next i 18 19 MsgBox "完了しました" 20End Sub 21 22Private Sub testSub(ByRef ws As WorkSheet) 23 24 Dim rCount As Long '行数 25 'ワークシートオブジェクトの行数を取得する 26 rCount = ws.Cells(Rows.Count, 1).End(xlUp).Row 27 28 '配列を用意 29 Dim arr() As Variant 30 'arr(rCount-2,8)の配列を作る 31 arr = ws.Range("A3:H" & rCount).Value 32 33End Sub

投稿2019/03/08 15:02

編集2019/03/09 03:00
hatena19

総合スコア33699

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

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

nstto12

2019/03/09 02:47

アドバイスありがとうございます! 引数でWorksheets(i)は渡せないよなあと思ってましたがこうすればよかったんですね。 引数をwsだけにすればたしかにtestSubもかなりすっきり書けそうです。
guest

0

こんな感じにしたらどうだろうか?
参考になれば、、、、

VBA

1Option Explicit 2 3Sub testMain() 4 Dim wbTarget As Workbook '操作対象のワークブックオブジェクト 5 Dim ws As Worksheet '各シート 6 Dim sResult As String '結果を文字列で記録(カンマ区切り) 7 dim v '配列の受け皿 8 9 On Error Resume Next 10 Set wbTarget = GetBook(Application.GetOpenFilename(",*.xlsx")) 11 On Error GoTo 0 12 If wbTarget Is Nothing Then Exit Sub 13 14 '取得したブックのシート数分処理を繰り返す 15 For Each ws In wbTarget.Worksheets 16 GetRowsCount ws, sResult 17 Next 18 19 MsgBox Mid(sResult, 2) 20 v = Split(Mid(sResult, 2),",") 21 Stop 22End Sub 23 24'======================================================================= 25Private Function GetRowsCount(ByRef ws As Worksheet, ByRef s As String) 26 With ws.UsedRange 27 s = s & "," & .Cells(.Cells.CountLarge).Row 28 End With 29End Function 30 31'======================================================================== 32Private Function GetBook(ByVal sFullPath As String) As Workbook 33 Dim wb As Workbook 34 Dim sFName As String 35 Dim i As Long 36 37 If sFullPath = "FALSE" Then Exit Function 38 39 i = InStrRev(sFullPath, "\") 40 sFName = Mid(sFullPath, i + 1) 41 42 On Error Resume Next 43 Set wb = Workbooks(sFName) 44 On Error GoTo 0 45 If wb Is Nothing Or wb.FullName <> sFullPath Then 46 If sFName = wb.Name Then wb.Close True 47 Set wb = Workbooks.Open(sFullPath) 48 End If 49 50 Set GetBook = wb 51End Function 52

シートの全部のセルが空白だとエラーになるのだろうか。。。。動作確認してません。

投稿2019/03/08 13:56

mattuwan

総合スコア2136

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

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

nstto12

2019/03/09 03:05

ちょっと理解するのに時間がかかりました。。 詳細なお手本を記載いただき感謝します。 まだまだ完成形には遠いので参考にさせていただきます!
guest

0

ベストアンサー

以下2点修正してみてください。

  1. Dim arr() As VariantDim arr As Variant にする → hatena19さんのご指摘より、修正の必要がないことがわかりました。誤情報を書いてしまい申し訳ありません。

rangeの範囲の中身を配列に代入するときに、変数宣言で()を付ける必要はなかったかと思います。

  1. Range("A3:H" & rCount).Range("A3:H" & rCount) にする

.をつけないとWithステートメントの意味がありません。
Range("A3:H" & rCount)はアクティブシートのRangeを指しているため、アクティブなシートの情報しか得られないのです。.をつけることで、Withの後に指定したもの(今回ならwb.Worksheets(i)を省略しますよ、という意味になります。

投稿2019/03/08 12:54

編集2019/03/08 15:01
nmoa

総合スコア54

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

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

hatena19

2019/03/08 14:42

> 変数宣言で()を付ける必要はなかったかと思います。 ()はあってもなくても同じ動作になりますが、() を付けたほうが内部的にはシンプルになるそうです。 VBA 高速化テクニック ~ 配列とセルの相互転記 - t-hom’s diary https://thom.hateblo.jp/entry/2015/08/30/141854
nmoa

2019/03/08 14:59

そうなのですね、全く知りませんでした。回答の方は修正させていただきます。ご教示いただきありがとうございます。 せっかくなのでVBAリファレンスを漁ってみたのですが、 - 配列宣言のページ( https://docs.microsoft.com/ja-jp/office/vba/language/concepts/getting-started/declaring-arrays ) - Variantのページ( https://docs.microsoft.com/ja-jp/office/vba/language/concepts/getting-started/understanding-variants ) ではこの挙動は触れられていないようでした。どこかに記述があったりするのでしょうかね。。
hatena19

2019/03/08 15:07

リンク先の後の方に解説がありますが、 () がないと Variant型の中にVariant1型配列が格納される () があると、Variant型の動的配列になる ということがローカルウィンドウで確認できます。
nmoa

2019/03/08 15:28

Variant型の変数にVariant型(他の型でもいいですが)の配列そのものを格納できる、というのがリファレンスに書かれていることを期待したのですが、自分の探した範囲ではそれをはっきり書いた記述が見つかりませんでした。(リンク先に「実際には参照ポインタだと思う。」と書かれていますがその辺りも関係しているのでしょうか…)
nstto12

2019/03/09 02:42

そのものズバリなご指摘ありがとうございます! Withステートメントも見様見真似で使っていたので言われるまで全く気が付きませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問