繰り返し処理を使いこなそう。

データのある分だけ、同じ処理を実行させたいときがあります。
そのときに使うのが、For Next文やDo Loop文です。

1.基本は、For〜Next文。

繰り返し処理の基本は、For Next文です。
決まった回数の繰り返し処理を行うのが得意です。
 右のようにしたい 

例えば、上のようなデータを、奇数と偶数に振り分ける場合だと、下のようになります。

Sub test()

  Dim R As Integer

  For R = 2 To 10 ←@
    Select Case Cells(R, 1) Mod 2 ←A
      Case Is = 1 ←B
        Cells(R, 2) = Cells(R, 1)
        Cells(R, 1) = ""

      Case Else ←C
        Cells(R, 3) = Cells(R, 1)
        Cells(R, 1) = ""
    End Select
  Next R ←D

End Sub
@ ここで、2行目から10行目まで処理をすることを設定します。
  (数が、2から1つずつ増えて、10になるまで処理をする。)

A セルの値を2で割った余りで条件分岐します。

B 余りが1のときは、2列目の奇数の欄に書き込み、元のセルは空欄にします。

C それ以外の時は、3列目の偶数欄に書き込み、元のセルは空欄にします。

D ここまでの処理を繰り返すよう設定します。
上の書き方が基本ですが、次のようなこともできます。

For R = 2 To 10 Step 2  ← 2から10まで、2つずつ数字を増やしていく。(2つ飛ばしの意味)

For R = 10 To 2 Step -2  ← 10から2まで、2つずつ数字を減らしていく。

2.データ数が決まってなく、ちょくちょく変わることがある場合(Do〜Loop文)

いつも同じ個数のデータを処理する場合は、For Next文で回数を指定すればいいのですが、
毎回、データの数が違うとなると、そのままではうまく処理できません。
そういうときには、便利な Do Loop文があります。
連続してデータが続く場合、終わりまで処理を続けてくれます。

Sub test3()

  Dim R As Integer

  R = 2 ←@
  Do Until Cells(R, 1) = "" ←A
    Select Case Cells(R, 1) Mod 2
      Case Is = 1
        Cells(R, 2) = Cells(R, 1)
        Cells(R, 1) = ""

      Case Else
        Cells(R, 3) = Cells(R, 1)
        Cells(R, 1) = ""
    End Select

    R = R + 1 ←B
  Loop ←C

End Sub
@ ここで、何行目から実行するか数値を設定します。(カウンタ)

A 1列目のセルが空になるまで、処理を実行します。

B カウンタを1つ、増やします。


C ここまでの範囲を繰り返します。
Do Loop文では、カウンタという変数を1つ用意し、進み方を設定しなければなりません。B
上の場合でいうと、Rです。
1回処理が終わる毎に、カウンタを1つ増やして、1つ下のセルを指定しています。
これをしないと、同じセルで無限に処理を続けていくことになります。
(For Next文は、行頭で設定しています。)

Do の横にある、Until は、「条件を満たすまで実行する」という意味です。
したがって、上の場合は、空のセルが見つかるまで実行し続けます。

反対に、While もあります。(「条件を満たす間実行する」という意味
これを使って同じ処理をさせようとするなら、
Do Until Cells(R, 1) = "" は、下のようになります。
Do While Cells(R, 1) <> "" となります。

また、Until や While は行末に付けることもできます。

Do
Loop Until Cells(R, 1)

行頭に付けた場合は、条件が合わないと1回も処理をしずに次に移ってしまうのに対して、
行末にに付けた場合は、必ず1回は処理をします。
このことを考えて、位置を決めます。(普通は、行頭でいいです。わかりやすいから。)

3.途中に空欄があるときは、やっぱりFor〜Next文

Do Loop文は、非常に便利ですが、途中に空欄があると、もうお手上げです。
空欄で、処理が止まってしまうからです。
そこで、空欄があっても処理を続けさせるには、ひと工夫してFor Next文を使います。
 右のようにしたい 

Sub test4()

  Dim 数 As Long ←@
  Dim R As Long ←@

  数 = Rows.Count ←A
  数 = Cells(数, 1).End(xlUp).Row ←B

  For R = 2 To 数 ←C
    Select Case Cells(R, 1) Mod 2
      Case Is = 1
        Cells(R, 2) = Cells(R, 1)
        Cells(R, 1) = ""
      Case Else
        Cells(R, 3) = Cells(R, 1)
        Cells(R, 1) = ""
    End Select
  Next R

End Sub
@ 変数の宣言を長整数型で行います。
  整数型(Integer)だと、オーバーフローしてしまうからです。

A セルの全行数を求めます。

B 最終行から、データのある最終行を探します。

C 範囲を2から、データのある最終行とします。
工夫してあるのは、@、A、Bで、データの最終行を求めていることです。
これで、空欄があっても最後まで処理してくれます。 

4.こんなFor文もある。(For Each 〜 In 〜)

For文の使い方として、『ある範囲や全ワークシートなどを対象にして繰り返し処理を行う』というものがあります。
位置などの変数を使わなくてもいいので、上手に使うと非常に便利です。

ある範囲で実行 (実行前) →
→ ある範囲で実行 (実行後)
 Sub test01()

  Dim 範囲 As Range ←@
  Dim tmp As Range ←A

  Set 範囲 = Range("a1:d5") ←B

  For Each tmp In 範囲 ←C
    tmp.Value = tmp.Value + 1 ←D
  Next tmp

End Sub
≪ある範囲の数値全部に、1を足す処理≫


@A セルや範囲を扱うのでRangeで宣言します。

B 範囲という変数に代入します。

C 範囲の中から、1つずつセルを取り出します。

D tmpがセルを扱っているので、セルの何を扱うのか、細かく指定します。
  この場合は、値なので、Value です。
  入っている値に、+1したものを元のセルに代入しています。
 
全ワークシートを対象に実行 (実行前) →  → 全ワークシートを対象に実行 (実行後)
 
Sub test02()

  Dim tmp As Worksheet ←@
  Dim R As Integer

  For Each tmp In Worksheets ←A
    R = R + 1 ←B
    Cells(R, 1) = tmp.Name ←C
  Next tmp

End Sub
≪すべてのワークシート名をセルに書き出す処理≫


@ ワークシートを扱うのでWorksheetで宣言します。

A 全ワークシートの中から、1つずつワークシートを取り出します。

B 書き込むセルを1つずつ下に下げるため、+1します。

C tmpがワークシートを扱っているので、ワークシートの何を扱うのか、細かく指定します。
  この場合は、名前なので、Name です。
  全部のワークシートの名前を、セルに書き出しています。
全オートシェイプを対象に実行 (実行前) →
 
→ 全オートシェイプを対象に実行 (実行後)
Sub test03()

  Dim tmp As Shape ←@
  Dim L As Integer

  For Each tmp In ActiveSheet.Shapes ←A
    tmp.Top = 0 ←B
    tmp.Left = L ←C
    L = L + 80 ←D
  Next tmp

End Sub
≪すべてのシェイプを順に並べる処理≫ 


@ シェイプを扱うので、Shapeで宣言します。

A アクティブなシートの全シェイプの中から、1つずつシェイプを取り出します。

B ワークシート上でのシェイプの上端の位置を決めます。ここでは0なので、シートの一番上になります。

C ワークシート上でのシェイプの左端の位置を決めます。ここでは80ずつ増やしていくので、右に順番に並びます。