はじめに:二重ループの重要性
Excel VBAにおける二重ループは、データ処理の効率を飛躍的に向上させるための強力なツールです。配列の操作、複雑な条件分岐、複数シートへのデータ展開など、実務で遭遇する多くの場面でその威力を発揮します。しかし、その構造の複雑さから、初学者にとっては理解が難しいと感じられることも少なくありません。
このブログ記事では、VBA練習問題3「二重ループの練習」の解答を提示し、そのコードがなぜそのように動作するのかを詳細に解説します。さらに、二重ループを効果的に活用するための実務的なアドバイスと、学習を深めるためのヒントを提供します。この記事を読み終える頃には、二重ループに対する苦手意識を克服し、自信を持って使いこなせるようになっているはずです。
練習問題3:問題の復習
まず、練習問題3の内容を再確認しましょう。
**問題:**
ExcelシートにA列からD列まで、1行目から10行目までの範囲にランダムな数値(1から100の範囲)を100個生成してください。その後、VBAを使用して、生成された数値の中から50以上の数値をE列に抽出し、それぞれの数値が何行目から取得されたのかをF列に記録してください。
この問題は、二重ループを使って指定範囲にデータを入力し、さらにそのデータを条件で絞り込んで別の列に出力するという、典型的な二重ループの応用例です。
解答コードの提示
それでは、上記の練習問題に対する解答コードを以下に示します。
Sub 二重ループ練習問題3解答()
Dim ws As Worksheet
Dim i As Long
Dim j As Long
Dim rowIndex As Long
Dim count50OrMore As Long
' 作業シートを設定
Set ws = ThisWorkbook.Sheets("Sheet1") ' 必要に応じてシート名を変更してください
' 既存のデータをクリア(必要であれば)
ws.Cells.ClearContents
' 1. A列からD列、1行目から10行目にランダムな数値を生成
Randomize ' 乱数生成器を初期化
For i = 1 To 10
For j = 1 To 4
ws.Cells(i, j).Value = Int((100 * Rnd) + 1) ' 1から100のランダムな整数を生成
Next j
Next i
' 2. E列とF列の準備(ヘッダー設定など)
ws.Cells(1, 5).Value = "50以上の数値"
ws.Cells(1, 6).Value = "元の行番号"
count50OrMore = 2 ' データは2行目から書き込むため初期値を2とする
' 3. 生成された数値の中から50以上の数値を抽出し、E列とF列に記録
For i = 1 To 10 ' 各行をチェック
For j = 1 To 4 ' 各列をチェック
If ws.Cells(i, j).Value >= 50 Then
ws.Cells(count50OrMore, 5).Value = ws.Cells(i, j).Value ' E列に数値を格納
ws.Cells(count50OrMore, 6).Value = i ' F列に元の行番号を格納
count50OrMore = count50OrMore + 1 ' 次の書き込み位置へ
End If
Next j
Next i
MsgBox "処理が完了しました。", vbInformation
End Sub
コードの詳細解説
この解答コードは、大きく分けて3つのステップで構成されています。
ステップ1:ランダムな数値の生成
Randomize ‘ 乱数生成器を初期化
For i = 1 To 10
For j = 1 To 4
ws.Cells(i, j).Value = Int((100 * Rnd) + 1) ‘ 1から100のランダムな整数を生成
Next j
Next i
* `Dim i As Long`, `Dim j As Long`: ループカウンタとして使用する変数を宣言します。`Long`型は、大量のデータを扱う場合でもオーバーフローの心配がなく推奨されます。
* `Set ws = ThisWorkbook.Sheets(“Sheet1”)`: 操作対象のワークシートを取得します。`ThisWorkbook`は、VBAコードが記述されているブック自身を指します。`Sheets(“Sheet1”)`は、”Sheet1″という名前のシートを指定しています。もしシート名が異なる場合は、適切に変更してください。
* `ws.Cells.ClearContents`: 実行前にシートの内容をクリアしています。これは、前回の実行結果が残っている場合に誤った結果にならないようにするためです。必要に応じてコメントアウトするか削除してください。
* `Randomize`: このステートメントは、乱数生成器を初期化します。`Rnd`関数は、呼び出されるたびに擬似乱数を返しますが、`Randomize`を実行しないと、プログラムを実行するたびに同じ乱数列が生成されてしまうことがあります。`Randomize`を一度実行することで、毎回異なる乱数列が生成されるようになります。
* `For i = 1 To 10`: 外側のループです。ここでは、行番号を1から10まで繰り返します。
* `For j = 1 To 4`: 内側のループです。ここでは、列番号を1から4まで繰り返します。
* `ws.Cells(i, j).Value = Int((100 * Rnd) + 1)`: この部分で、指定されたセルの値にランダムな数値を設定します。
* `Rnd`: 0以上1未満のランダムな単精度浮動小数点数を返します。
* `100 * Rnd`: 0以上100未満のランダムな単精度浮動小数点数を返します。
* `(100 * Rnd) + 1`: 1以上101未満のランダムな単精度浮動小数点数を返します。
* `Int(…)`: 小数点以下を切り捨て、整数部分のみを取得します。これにより、1から100までのランダムな整数が得られます。
* `ws.Cells(i, j)`: 指定された行(`i`)と列(`j`)のセルを参照します。例えば、`i=1`, `j=1`ならA1セル、`i=5`, `j=3`ならC5セルとなります。
この二重ループにより、A1からD10までの10行×4列の範囲に、合計40個のランダムな数値が生成されます。
ステップ2:E列とF列の準備
ws.Cells(1, 5).Value = “50以上の数値”
ws.Cells(1, 6).Value = “元の行番号”
count50OrMore = 2 ‘ データは2行目から書き込むため初期値を2とする
* `ws.Cells(1, 5).Value = “50以上の数値”`: E1セルにヘッダーテキスト「50以上の数値」を設定します。
* `ws.Cells(1, 6).Value = “元の行番号”`: F1セルにヘッダーテキスト「元の行番号」を設定します。
* `count50OrMore = 2`: これは、抽出したデータをE列とF列に書き込む際の開始行番号を管理するための変数です。ヘッダーが1行目にあるため、実際のデータは2行目から書き込みたいからです。この変数は、後続のループでデータが1行書き込まれるたびにインクリメントされます。
ステップ3:数値の抽出と記録
For i = 1 To 10 ‘ 各行をチェック
For j = 1 To 4 ‘ 各列をチェック
If ws.Cells(i, j).Value >= 50 Then
ws.Cells(count50OrMore, 5).Value = ws.Cells(i, j).Value ‘ E列に数値を格納
ws.Cells(count50OrMore, 6).Value = i ‘ F列に元の行番号を格納
count50OrMore = count50OrMore + 1 ‘ 次の書き込み位置へ
End If
Next j
Next i
* `For i = 1 To 10`: 外側のループで、処理対象の行を1行目から10行目まで繰り返します。
* `For j = 1 To 4`: 内側のループで、各行のA列からD列までを繰り返します。
* `If ws.Cells(i, j).Value >= 50 Then`: 現在チェックしているセル(`ws.Cells(i, j)`)の値が50以上であるかを判定します。
* `ws.Cells(count50OrMore, 5).Value = ws.Cells(i, j).Value`: 条件を満たす場合、そのセルの値(50以上の数値)をE列(5列目)の`count50OrMore`行目に書き込みます。
* `ws.Cells(count50OrMore, 6).Value = i`: 同様に、そのセルの値がどの行(`i`)から取得されたのかをF列(6列目)の`count50OrMore`行目に書き込みます。
* `count50OrMore = count50OrMore + 1`: 1行分のデータをE列とF列に書き込んだので、次のデータを書き込むために`count50OrMore`変数を1増やします。これにより、データが連続してE列とF列に書き込まれていきます。
この二重ループにより、A1からD10の範囲全体を走査し、50以上の数値が見つかるたびにE列とF列に記録するという処理が実現されます。
二重ループを使いこなすための実務アドバイス
1. 変数の意味を明確にする
二重ループでは、外側のループと内側のループでそれぞれ異なる意味を持つ変数が使われます。例えば、今回の問題では `i` が「行」を、`j` が「列」を表していました。これらの変数が何を表しているのかをコードの冒頭やコメントで明確にすることで、コードの可読性が格段に向上します。`rowIndex`, `colIndex`, `currentRow`, `currentColumn` のような、より意味の分かりやすい変数名を使用することも検討しましょう。
2. ループの範囲を正確に指定する
ループの開始値と終了値を間違えると、意図しない範囲のデータが処理されたり、エラーが発生したりします。特に、データが1行目から始まっているのか、2行目から始まっているのか、あるいは最終行が固定されているのか、動的に取得する必要があるのかなどを正確に把握することが重要です。`LastRow = ws.Cells(Rows.Count, “A”).End(xlUp).Row` のようなコードで最終行を動的に取得するテクニックも、二重ループと組み合わせてよく使われます。
3. ネストの深さに注意する
二重ループ(二重ネスト)は一般的ですが、さらに三重、四重とネストが深くなると、コードの可読性が著しく低下し、デバッグも困難になります。もし三重以上のループが必要になった場合は、処理を別のプロシージャ(SubまたはFunction)に分割したり、配列やDictionaryオブジェクトなどを活用して、ネストの深さを浅くできないか検討しましょう。
4. 処理の途中でループを抜ける (Exit For)** 今回の問題では、すべてのデータを処理しきる必要がありましたが、実務では「条件を満たす最初のデータが見つかったら処理を終了したい」といったケースもよくあります。その場合、`Exit For` ステートメントを使用することで、内側のループまたは外側のループを強制的に終了させることができます。 ‘ 例:最初に50以上の数値が見つかったらループを終了する Dim foundFirst As Boolean foundFirst = False For i = 1 To 10 For j = 1 To 4 If ws.Cells(i, j).Value >= 50 Then ‘ 処理を実行 foundFirst = True Exit For ‘ 内側のループを抜ける End If Next j If foundFirst Then Exit For ‘ 外側のループも抜ける End If Next i 5. デバッグ機能を活用する (F8キー)** 二重ループのような複雑な処理を理解するには、ステップ実行が非常に有効です。VBE(Visual Basic Editor)でコードの先頭にブレークポイントを設定し、F5キーで実行します。そして、F8キーを何度か押して1行ずつコードを実行しながら、変数の値がどのように変化していくかを確認しましょう。特に、内側のループがどのように複数回繰り返されるのかを視覚的に追うことで、理解が深まります。 6. 処理速度を意識する
Excel VBAは、直接的な手作業に比べると高速ですが、大量のデータを扱う場合、処理速度が問題となることがあります。
* **`ScreenUpdating`と`Calculation`**: 画面の更新を停止 (`Application.ScreenUpdating = False`) したり、Excelの自動計算を無効化 (`Application.Calculation = xlCalculationManual`) したりすることで、処理速度を向上させることができます。処理の最後に元に戻すのを忘れないようにしましょう。
* **配列の利用**: セルへの直接アクセスは比較的遅いため、大量のデータを一度配列に取り込み、配列上で処理を行ってから、最後に結果をセルに書き戻す方が高速な場合があります。
‘ 配列を使った例(一部抜粋)
Dim dataArray As Variant
Dim outputArray() As Variant ‘ 動的配列
Dim outputRow As Long
dataArray = ws.Range(“A1:D10”).Value ‘ 範囲を一度に配列に読み込む
outputRow = 1
ReDim outputArray(1 To 100, 1 To 2) ‘ 適切なサイズで動的配列を宣言
For i = 1 To UBound(dataArray, 1) ‘ 配列の行数
For j = 1 To UBound(dataArray, 2) ‘ 配列の列数
If dataArray(i, j) >= 50 Then
outputArray(outputRow, 1) = dataArray(i, j)
outputArray(outputRow, 2) = i
outputRow = outputRow + 1
End If
Next j
Next i
‘ 結果をシートに書き戻す
ws.Range(“E2”).Resize(outputRow – 1, 2).Value = outputArray ‘ Resizeで書き込む範囲を調整
まとめ:二重ループは強力な武器
今回の練習問題3の解答と解説を通して、VBAにおける二重ループの基本的な使い方から、より実践的な応用までを網羅しました。二重ループは、一見複雑に見えるかもしれませんが、その構造を理解し、変数の役割を把握すれば、非常に強力なデータ処理ツールとなります。
今回学んだ内容を活かして、さらに様々な練習問題に取り組むことで、二重ループのスキルは着実に向上します。ぜひ、ご自身の業務で抱えている課題に二重ループを適用できないか検討してみてください。コードを書き、実行し、デバッグするというサイクルを繰り返すことが、VBAマスターへの最短ルートです。
このブログ記事が、あなたのVBA学習の一助となれば幸いです。
