こんにちは!マクロの記録から一歩抜け出して、「自分の手で自由自在にExcelを動かしたい」と熱心に学んでいるあなたへ。
Excel VBAを書いていると、何度も何度も繰り返し処理を行う場面に出会いますよね。「データを上から順に見たい」「シートを一枚ずつめくって確認したい」――そんなときに必ず使うのがループ(繰り返し)処理です。
ここで多くの人が「あれ、どっちを使えばいいんだっけ?」と立ち止まるのが、`For…Next` と `For Each…Next` の使い分けです。
「とりあえず動けばいいや」と適当に選んでいると、処理が異様に遅くなったり、思わぬエラーでマクロが止まったりしてしまいます。でも、ご安心ください。それぞれのキャラクターと使い所さえ分かってしまえば、もう迷うことはありません。
今回は、現場のプロたちがどのようにこの2つを使い分けているのか、パフォーマンスの裏側も含めて優しく、そして深く解説していきますね。ここをクリアすれば、あなたのVBAスキルは一段と洗練されますよ!
—
1. 2大ループの基本キャラクターを知ろう
まずは、この2つのループが「何をどう見ているのか」をイメージで掴みましょう。
① `For…Next` =「番号(インデックス)で数える職人」
- イメージ: 「1番目、2番目、3番目……」と、順番に番号を指定して引き出しを開けていくスタイル。
- 得意なこと: 「3行目から100行目まで」「2個飛ばしで」といった、数字をベースにした規則正しい処理。
② `For Each…Next` =「目の前にあるものを次々に手にとる職人」
- イメージ: 段ボール箱の中にある商品を、番号を気にせず「次、これ! 次、これ!」と端から手に取っていくスタイル。
- 得意なこと: コレクション(シートの集まり、セルの集まりなど)の中にある「実体(オブジェクト)」を丸ごと相手にする処理。
—
2. 【実例コード】どう書くのか見比べてみよう
百聞は一見にしかず。A1からA10セルに「テスト」と文字を入れるコードを、両方の書き方で見比べてみましょう。
`For…Next` の場合(数字で管理)
Sub Sample_ForNext()
Dim i As Long
‘ 1から10までの「数字」を使ってループする
For i = 1 To 10
Cells(i, 1).Value = “テスト”
Next i
End Sub
解説:
`i` という変数が、1、2、3……と10まで変化します。`Cells(i, 1)` は、「i行目の1列目のセル」を指定しているので、意図した通りのセルに書き込むことができます。
—
`For Each…Next` の場合(実体を直接つかむ)
Sub Sample_ForEach()
Dim rng As Range
Dim targetCell As Range
‘ 対象となるセル範囲をセット
Set rng = Range(“A1:A10”)
‘ 範囲内のセルを1つずつ「実体」として取り出す
For Each targetCell In rng
targetCell.Value = “テスト”
Next targetCell
End Sub
解説:
ここでは「何番目か」という数字は一切登場しません。`Range(“A1:A10”)` というセルの集まり(コレクション)から、1つずつセルという「実体(オブジェクト)」を `targetCell` に放り込んでいきます。
—
3. どっちが速い? パフォーマンスの真実と使い分けの極意
さて、ここからが本題です。「どっちを使っても同じなら、短い方がいいや」と思っていませんか? 実は、処理のスピードにおいて明確な違いが出るケースがあります。
結論:使い分けの黄金律
1. 「セル範囲(Range)」や「シート(Worksheets)」をただ順番に舐めるだけなら:
👉 `For Each…Next` が速くてスマート!
2. 「行番号そのもの」を使って計算をしたり、特定の行を飛ばしたり、行を削除したりするなら:
👉 `For…Next` の一択!
なぜ `For Each` の方がセル操作で速いのか?
Excel VBAの最大のボトルネックは、VBAとExcelの本体(ワークシート)の間で行われる「通信」です。
`For…Next` で `Cells(i, 1)` と書くたびに、VBAはExcelに対して「おい、i行目の1列目のデータをくれ!」と毎回パスを出しています。これが積もると地味に動作が重くなります。
一方、`For Each` は最初に範囲をごっそり掴んでメモリ上に保持するため、VBAとExcelの往復回数が少なくなり、結果として処理スピードが向上する傾向にあります。
—
4. ⚠️ 初学者が絶対にハマる「落とし穴」とエラー対策
最後に、実務でよくある失敗パターンをご紹介します。ここを知っておくだけで、無駄な残業を防げますよ!
罠その1:`For Each` でループ中に「行を削除」してはいけない!
「条件に一致する行を削除したい!」というとき、`For Each` を使うとエラーになるか、判定がバグってデータを盛大に消し飛ばします。
- NGな例(For Eachで削除):
‘ ※絶対にやってはいけない例
Dim c As Range
For Each c In Range(“A1:A10”)
If c.Value = “削除” Then
c.EntireRow.Delete ‘ ←ループの途中で足場を壊すのでバグる!
End If
Next c
- 正解(For…Next を「下から上へ」回す):
行を削除したり挿入したりする場合は、必ず `For…Next` を使い、下から逆順(Step -1)で回します。
Dim i As Long
‘ 下の行(10行目)から上の行(1行目)に向かってカウントダウン
For i = 10 To 1 Step -1
If Cells(i, 1).Value = “削除” Then
Cells(i, 1).EntireRow.Delete
End If
Next i
(上から順に消すと、行番号がズレて判定漏れが起きるため、下から消すのが鉄則です!)
—
まとめ
いかがでしたでしょうか?
- `For…Next` は、数字でコントロールする万能選手。行の削除や複雑な位置計算が必要なときに頼りになる。
- `For Each…Next` は、目の前のオブジェクトを優しく順番に撫でていくような、コレクション操作のスピードスター。
この2つの特性を理解しておけば、シチュエーションに応じて最適なコードが書けるようになり、マクロの動作スピードも見違えるほど快適になります。
「ここをクリアすれば、Excel VBAの基本はバッチリですよ!」
自信を持って、次の自動化の扉を開いていきましょう。あなたのVBAライフを応援しています!
