【VBAマクロ】For Eachの使い方を完全解説!【For Nextの違いは?】

スポンサードリンク
VBA
  • エクセルのマクロを勉強し始めたんだけど、For Eachって何?
  • For Each と For Next(通常のFor文)との違いが知りたい

このようなお悩みをお持ちですか?
この記事を読むことで、下記のことがわかります。

  • For Eachの基本構文を学べる
  • For Each と For Nextの違いを知れる
  • For Eachの使い方や書き方がわかる

VBAマクロ歴3年の私が、できるだけわかりやすく解説いたします。

※わかりやすさを重視しております。厳密には解釈が異なる場合がありますことをご了承ください。

スポンサードリンク

For Eachとは?

「For Each」は、コレクションや配列の要素をまとめて処理できるループ構文です。
難しい用語がいろいろ出てきましたね。

まずコレクションとは、エクセルブックやシート、範囲指定したセルなどの集合体を指します。
マンガ全巻、ゴルフクラブ一式、みたいなものだと思ってください。

配列は、変数が集まったものです。
下記記事でわかりやすく解説しておりますので、詳しく知りたい方はご参考ください。

配列やコレクション1つ1つの領域を要素といいます。

ループ構文は、繰り返し処理を行う構文です。
なのでここまでを総合して簡単に説明すると、
「For Each」は集合体を一括処理できる繰り返し構文
といった具合でしょうか。

繰り返し処理で代表的なものには「For Next(通常のFor文)」があります。
では「For Next」と「For Each」はどう違うのか?について解説していきます。

For Nextとの違い

「For Next」と「For Each」との違いを簡単にまとめてみました。

【For Next】

  • 使い方:指定回数の繰り返し
  • 例:For i = 1 To 10
  • 処理速度:遅い場合がある

【For Each】

  • 使い方:コレクションや配列を繰り返し処理
  • 例:For Each cell In Range(“A1:A5”)
  • 処理速度:速い

なかなかピンとこないと思いますので、それぞれの構文を比較してみましょう。

Sub ForNext()
    Dim i As Integer
    For i = 1 To 5
        Range("A"&i).Value = "Utatane"
    Next i
End Sub
Sub ForEach()
    Dim cell As Range
    For Each cell In Range("A1:A5")
        cell.Value = "Utatane"
    Next cell
End Sub

どちらも「A1~A5セル」に「Utatane」と書き込むループ文です。

ループ例

まず今回の例では、ぱっと見て下の「For Each」の方が、「A1~A5セル」まで処理されていることがわかりやすいかと思います。

「For Next」の方は、指定回数分セルを下に移動して書き込んでいます。
セル1つ1つを読み込むため、処理に時間がかかる場合があります。
紙を1枚1枚切っているようなイメージです。

いっぽう「For Each」は、あらかじめ範囲指定されたセル(A1~A5)を端から処理しているといった具合です。
あらかじめ範囲を指定しているため、処理が速く終わる傾向にあります。
紙を5枚まとめて切っているような感じでしょうか。

では、そんな「For Each」の基本構文について見ていきましょう。

スポンサードリンク

For Eachの基本構文

前項のコードを例に挙げながら、細かく見ていきましょう。

Sub ForEach()
    Dim cell As Range
    For Each cell In Range("A1:A5")
        cell.Value = "Utatane"
    Next cell
End Sub

それぞれの役割は以下のとおりです。

Sub ForEach()
    「変数の宣言」
    For Each 「単体」 In 「集合体」
        「ループさせる処理」
    Next 「変数」
End Sub

1つ1つ解説していきます。

プロシージャの作成

Sub ForEach()

End Sub

プロシージャなど、マクロの基礎は下記記事でわかりやすく解説しております。
コードだけではなく、開発タブの表示からマクロの保存まで知りたい方はご参考ください。

変数の宣言

    Dim cell As Range

上記コードにて、以降使用する変数の宣言を行っております。
変数や宣言についての詳しい解説は、下記記事をご参考ください。

ループ文

    For Each cell In Range("A1:A5")
        cell.Value = "Utatane"
    Next cell

上記コードにて、ループ処理を実行しています。
書き方は下記のような感じです。

    For Each 「単体」 In 「集合体」
        「ループさせる処理」
    Next 「変数」

では、プログラムの流れを簡単に見ていきましょう。

「集合体(今回はA1~A5セル)」の中から1つ(A1セル)が「単体(cell)」に入る。
cell(A1)に「Utatane」が書き込みされる。
次のセルに移る。
  ↓
「集合体(今回はA1~A5セル)」の中から1つ(A2セル)が「単体(cell)」に入る。
cell(A2)に「Utatane」が書き込みされる。
次のセルに移る。
  ↓
同様に、「A3」「A4」セルも処理され、
A5セルが処理されたら、ループが終了する。

まだピンと来ないかもしれませんので、
配列やシートなど、他の例も見ていきましょう。

スポンサードリンク

For Eachの使い方いろいろ

配列のループ処理

Sub 配列のループ処理()
    Dim arr As Variant
    arr = Array("野球", "サッカー", "バレーボール")

    Dim item As Variant
    For Each item In arr
        MsgBox item
    Next item
End Sub

配列である「arr」に「野球」「サッカー」「バレーボール」という値が入っています。
この配列の値を「メッセージボックスで表示」という処理を繰り返していくというマクロです。
野球を表示→サッカーを表示→バレーボールを表示

配列のループ処理

シートのループ処理

下記VBAコードは、各シートのA1セルにそれぞれのシート名を書き込みするループ文です。

Sub シートのループ処理()
    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Worksheets
        ws.Cells(1, 1).Value = "シート名:" & ws.Name
    Next ws
End Sub

Sheet1に書き込み→Sheet2に書き込み→Sheet3に書き込みと処理がループします。

シートのループ処理

条件付きでセルを変更(特定の値を持つセルのみ処理)

下記VBAコードは、A1~A5セルの値が「OK」であるときのみ、セルを緑色にするループ文です。

Sub 条件付きでセルを変更()
    Dim cell As Range
    For Each cell In Range("A1:A5")
        If cell.Value = "OK" Then
            cell.Interior.Color = RGB(0, 255, 0)
        End If
    Next cell
End Sub
条件付きで分岐するループ処理

条件分岐(セルの値が「OK」であるか否かを判別する)にはIfを使用しています。
Ifは下記記事でわかりやすく解説しておりますので、ご参考ください。

A1(値がOKかどうかを判別し、セルを緑色に)→A2(〃)~→A5(〃)

指定のシートを除外して処理

下記VBAコードは、「マスターデータ」という名前のシート以外のシートについて、
セルデータを消去する例です。

Sub 指定のシートを除外して処理()
    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Worksheets
        If ws.Name <> "マスターデータ" Then
            ws.Cells.ClearContents  ' 指定シート以外のデータをクリア
        End If
    Next ws
End Sub

1つ目のシート(シート名がマスターデータ以外ならデータ消去)→2つ目のシート(〃)→・・・

スポンサードリンク

For Eachの注意点

便利な「For Each」ですが、注意点があります。

配列の値を直接変更できない

下記VBAコードは、配列から値を取り出して2倍するという処理を繰り返した例です。

Sub 注意点1()
    Dim arr As Variant
    arr = Array(1, 2, 3)

    Dim i As Variant
    For Each i In arr
        i = i * 2
    Next i
    MsgBox arr(0) & arr(1) & arr(2)
End Sub

配列(arr)から取り出された値が変数(i)に入り、2倍されます。
iは2倍されて、それぞれ「2、4、6」という値になるのですが、
元の配列(arr)は2倍されず、もともとの値のままとなります。

注意点1

改善案としては、「For Each」を使わず、「For Next」を使います。
下記のVBAコードを見てください。

Sub 注意点1の改善案()
    Dim arr As Variant
    arr = Array(1, 2, 3)
    
    Dim i As Variant
    For i = 0 To 2
        arr(i) = arr(i) * 2
    Next i
    MsgBox arr(0) & arr(1) & arr(2)
End Sub

これで配列(arr)が2倍され、保存することができます。

注意点1の改善案

コレクションの順番が保証されるわけではない

「For Each」では、コレクション(集合体)の順番が保証されない場合があります。
今回は、「Sheet1~3」の各シート名を表示させた例です。

Sub 注意点2()
    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Worksheets
        MsgBox ws.Name
    Next ws
End Sub

【期待する順番】
Sheet1
Sheet2
Sheet3

【実際に出力される順番】
Sheet3
Sheet1
Sheet2
(予期しない順番になる可能性あり)

シートの順番を保証したい場合は、前項と同じく「For Next」を使い、Worksheets(i) のように明示的に順番を指定します。

Sub 注意点2の改善案()
    Dim i As Integer
    For i = 1 To ThisWorkbook.Worksheets.Count
        MsgBox ThisWorkbook.Worksheets(i).Name
    Next i
End Sub

これなら必ず見た目どおりの順番で表示されます。

スポンサードリンク

最後に

VBAのFor Eachについて解説いたしました。

当ブログでは、VBAマクロやPythonなど、時間を生み出すプログラミング術を公開しております。
この記事がわかりやすいと感じた方は、他の記事も読んでいってください。

最後までお読みいただき、ありがとうございました。がんばってください!

タイトルとURLをコピーしました