teratail header banner
teratail header banner
質問するログイン新規登録

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

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

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

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

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

3回答

3255閲覧

練習問題17(エクセルの神髄)を配列で実行したい

tatuya51

総合スコア23

VBA

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

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2021/05/05 13:50

0

0

エクセルの神髄の練習問題17について、回答通りの動作をを配列にて実行する方法を模索しております。
連想配列やユーザー定義型の使用も考えましたが、ブック名とブック名に対応するシート名を切り分けて配列に格納し、回答シートに吐き出せばいいかいまいちピンときません。
どなたかベストな記述を教えて頂けたら幸いです。よろしくお願いします。
練習問題17リンク

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

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

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

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

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

guest

回答3

0

ベストアンサー

一旦配列に格納して、それをシートに出力するようにしたい。
という質問だとして回答します。
尚、今回の回答として関係ない所は省いています。

VBA

1Private Type Book_Type 2 BookName As String 3 SheetNames() As String 4End Type 5 6Public Sub test() 7 Dim i As Long 8 Dim j As Long 9 Dim k As Long 10 11 Dim wb As Workbook 12 Dim ws As Worksheet 13 Dim wsAns As Worksheet 14 15 Set wsAns = Worksheets("練習17_回答") 16 17 Dim tBooks() As Book_Type 18 19 With Worksheets("練習17") 20 ReDim tBooks(.Cells(.Rows.Count, 1).End(xlUp).Row - 2) 21 For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row 22 Set wb = Workbooks.Open(.Cells(i, 1) & "\" & .Cells(i, 2), False, True) 23 tBooks(i - 2).BookName = wb.Name 24 ReDim tBooks(i - 2).SheetNames(wb.Sheets.Count - 1) 25 j = 0 26 For Each ws In wb.Sheets 27 tBooks(i - 2).SheetNames(j) = ws.Name 28 j = j + 1 29 Next 30 wb.Close SaveChanges:=False 31 Next 32 End With 33 34 k = 2 35 For i = 0 To UBound(tBooks) 36 wsAns.Cells(k, 1).Value = tBooks(i).BookName 37 For j = 0 To UBound(tBooks(i).SheetNames) 38 wsAns.Cells(k, 2).Value = tBooks(i).SheetNames(j) 39 k = k + 1 40 Next 41 Next 42 43End Sub 44 45

シンプルなのだとこんなのでいいんじゃないでしょうか。

投稿2021/05/05 22:26

xail2222

総合スコア1525

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

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

tatuya51

2021/05/06 14:48

ご回答ありがとうございます。 xail2222さんの回答は私が当初目指していた記述に近いものであり、ユーザー定義型内でさらに配列を宣言できるという発想が私には抜けておりましたので大変参考になりました。
xail2222

2021/05/07 00:59

今回の目的はtatuya51さんが、配列の使い方をマスターする事でしょうから いくつかのパターンを試してみるのが良いかと思います。 良いプログラムと配列の使い方の習得に役立つプログラムの評価基準は別物と思います。 その為「ベストな記述」と言うのは私には違和感がありました。
tatuya51

2021/05/08 00:38

xail2222さんのおっしゃる通り「ベストな記述」という表現はよくなかったですね。 今後気を付けたいと思います。
guest

0

書いてみた。

VBA

1Sub sample() 2 With Worksheets("練習17") 3 4 Dim arrBooks(), arrSheets() 5 Dim wPath, wBook 6 Dim i, j 7 Dim ws As Worksheet 8 9 For i = 2 To .Cells(.Rows.Count, 2).End(xlUp).Row 10 wPath = .Cells(i, 1).Value 11 wBook = .Cells(i, 2).Value 12 13 With Workbooks.Open(wPath & "\" & wBook) 14 For Each ws In .Worksheets 15 j = j + 1 16 ReDim Preserve arrBooks(j) 17 ReDim Preserve arrSheets(j) 18 If ws.Index = 1 Then arrBooks(j) = wBook 19 arrSheets(j) = ws.Name 20 Next 21 .Close False 22 End With 23 Next 24 End With 25 26 arrBooks(0) = "ブック名" 27 arrSheets(0) = "シート名" 28 29 For Each ws In Worksheets 30 If ws.Name = "練習17_回答" Then Exit For 31 Next 32 If Not ws Is Nothing Then ws.Delete 33 Worksheets.Add.Name = "練習17_回答" 34 Worksheets("練習17_回答").Cells.Resize(j + 1, 2).Value = WorksheetFunction.Transpose(Array(arrBooks, arrSheets)) 35 36End Sub 37

投稿2021/05/06 05:49

jinoji

総合スコア4592

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

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

tatuya51

2021/05/06 14:10

ご回答ありがとうございます。 1点質問ですが、最後の「WorksheetFunction.Transpose(Array(arrBooks, arrSheets))」について、それぞれ一次元配列であるarrBooksとarrSheetsをArray関数で二次元配列に変換しているという認識でよろしいでしょうか?(このようなArrayの使い方を初めて見たもので、、)
jinoji

2021/05/06 22:52

Arrayについてはご認識の通りです。 私も最初はこんな使い方は知らず、いろいろ試しているうちに見つけました。 出力を見越して最初から二次元配列で処理してもよいのですが、お題に沿ってブック名の配列、シート名の配列をそれぞれ用意した都合上、このようにしてみました。 まあ今回の場合、ループを回して一つずつ出力しても大して大変でもないと思いますが。
tatuya51

2021/05/08 00:33

Arrayはこのような使い方もできるのですね。 今後配列を扱うときの参考にさせていただきます。 ご回答ありがとうございました。
guest

0

「回答通りの動作をを配列にて実行する」目的は何でしょうか。

ブック数が多くて時間かかかるのでそれを高速化したい。
WEBで配列を使うと高速化できるという情報があるので、配列にしたら高速化できるだろ。

ということでしょうか。
配列で高速化できるは、セルの読み書きです。広範囲のセルの参照や書き込みを配列を使うと一度に読み書きできるので高速化できます。
今回の要件だと参照したいブックの数は多くても数百ですよね。それぐらいなら配列を使っても、直接セルに読み書きしてもそれほど差はでないと思います。

それよりもブックを一つずつ開いて閉じるという部分にはるかに時間がかかります。この部分を高速化できないかを検討するのが先決でしょう。「エクセルの神髄」さんのサイトに下記の情報があります。
この方法でシート名を取得すると高速化できるでしょう。

Excelファイルを開かずにシート名を取得|VBAサンプル集


一応、練習問題17(ブック・シートの操作の練習)解答|VBA練習問題解答の解答コードを配列を使用したものに書き直したコードです。(たいして高速化は期待できません。)

vba

1Sub 練習問題17() 2 Dim i As Long 3 Dim j As Long 4 Dim wb As Workbook 5 Dim ws As Worksheet 6 Dim wsAns As Worksheet 7 Application.DisplayAlerts = False 8 For Each ws In Worksheets 9 If ws.Name = "練習17_回答" Then 10 ws.Delete 11 Exit For 12 End If 13 Next 14 Application.DisplayAlerts = True 15 Set wsAns = Worksheets.Add(after:=Worksheets("練習17")) 16 wsAns.Name = "練習17_回答" 17 18 Dim aryQ 19 aryQ = Worksheets("練習17").Range("A1").CurrentRegion.Value '練習データを配列に格納 20 21 Dim aryAns() 22 ReDim aryAns(1 To 2, 1 To 2) '回答格納用配列 23 aryAns(1, 1) = "ブック名" 24 aryAns(2, 1) = "シート名" 25 26 '↓ブック名、シート名を回答用配列に格納 27 j = 2 28 For i = 2 To UBound(aryQ) 29 Set wb = Workbooks.Open(aryQ(i, 1) & "\" & aryQ(i, 2)) 30 aryAns(1, j) = wb.Name 31 For Each ws In wb.Sheets 32 aryAns(2, j) = ws.Name 33 j = j + 1 34 ReDim Preserve aryAns(1 To 2, 1 To j) 35 Next 36 wb.Close SaveChanges:=False 37 Next 38 39 '回答用配列を回答シートに出力 40 wsAns.Range("A1").Resize(j - 1, 2).Value = WorksheetFunction.Transpose(aryAns) 41 42End Sub 43

投稿2021/05/06 04:56

編集2021/05/06 05:40
hatena19

総合スコア34367

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

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

tatuya51

2021/05/06 14:44

ご回答ありがとうございます。 目的としては配列の扱いに慣れるという意味で練習問題を片っ端から配列を使用したやり方で実行しており、練習問題17でつまずいたので質問させていただきました。(他に良い練習法があれば教えて頂けると幸いです、、) またhatena19さんのご指摘通り、初心者ながら私も実務で多数のブックを扱うことがありますが、ブックを開いて閉じる作業を高速化するという観点は抜けており、大変参考になりました。 コードにつきましても2次元配列の扱い方について理解が浅かったためとても勉強になる内容でした。 ありがとうございました。
hatena19

2021/05/07 00:00

目的もなしになんでも配列にすればいいというものではありません。 配列にすることで高速化できるというのが最大のメリットです。それなし配列にしても無意味ですし、コードが複雑になり読みにくくなるというデメリットだけになります。 配列で高速化するには、Range.Value で一気に配列に読み込み、配列をRange.Value に一気に書き込む、という方法にします。 これにより、セルへのアクセスが2回ですみます。セルへのアクセスは重い処理なのでそれをなるべく少ないくするという考え方です。 ループでセルを一つずつ参照して、配列に格納する、 配列をループして、セル一つずつに代入していく、 という方法も確かに配列を使っていますが、高速化というメリットはないです。ただ単に複雑になるというデメリットだけになります。
tatuya51

2021/05/08 00:28

確かに実務においても何でもかんでも配列を使ってみようとしていたので改めようと思います。 ご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問