繰り返し処理(ループ)を行うためのステートメントである、
Do While~Loop文と、Do Until~Loop文の違いを解説します。
同じところ
どちらも繰り返し処理(ループ処理)を行うためのステートメントです。
For文が回数で繰り返しをコントロールするのに対し、
両者とも条件式によってループを続けるかを判定します。
違うところ
「条件を満たす間続ける」のがDo While文
「条件を満たしたら終わる」のがDo Until文です。
例えばA1セルからA10セルを処理する場合は、
R = 1 Do While R <= 10 Cells(R, 1) = ○○ R = R + 1 Loop R = 1 Do Until R > 10 Cells(R, 1) = ○○ R = R + 1 Loop
この2つのコードは全く同じ動きをします。
- Rが10以下の間は続ける
- Rが10を超えたら終わる
は同じ意味ですからね。
ということで、WhileとUntilは完全な反転関係にあり、
Do While R <= 10 Do Until Not(R <= 10)
と、WhileをUntil Notに機械的に書き換えることができます。
While文は「条件式がTrueの間続ける」、
Until文は「条件式がTrueになるまで=Falseの間続ける」なので、
Notでぴったり反転するのは、当たり前といえば当たり前ですね。
使い分け
ぶっちゃけどっちも使わなくていい気がします。
というのも、今回のA1セルからA10セルを処理する場合は、
' For文を使用 For R = 1 To 10 Cells(R, 1) = ○○ Next ' Do~Loop文を使用 R = 1 Do Cells(R, 1) = ○○ R = R + 1 If R = 11 Then Exit Do Loop
このようにFor~Next文と、Do~Loop文で書くことができます。
この二つはどちらも長所があり、
まず、「For文は簡単なループ処理なら短く簡潔」に書けます。
今回の「A1セルからA10セル」のような単純な処理の場合は、
間違いなくFor文が一番見やすいですね。
対して、「Do~Loop文は判定やカウンタのタイミングが自由自在でなんでもできる」というのが長所です。
ちょっと変ですが、
R = 0 Do R = R + 1 If R = 11 Then Exit Do Cells(R, 1) = ○○ Loop
こう書いても同じ動きをします。
- カウンタを進めるタイミング
- カウンタを進める数
- カウンタのないループの作成
- 終了判定と、終了時の最終処理の記述
を自由に決めることができるので、
複雑なループ処理を書くにはDo~Loop文を使います。
この2つのループ手法と比べると、Do While/Untilって中途半端なんですよね。
- Do~Loop文なら書けるけど、Do While~Loop文だと難しい
- Do While文で書けるような処理なら、For文で書いた方が読みやすい
という状況に陥りやすいので、意外と出番がありません。
ということで、ループを勉強したての方々は、
- 基本Forで書けるように頑張ってみて、
- 無理ならDo~Loop文で書く
という使い分けをまずは身に着けましょう。
Do WhileとDo Untilは、そんなものもあるんだな程度でいいと思います。
既存のマクロを読むために存在を知っておく意味はあると思いますが、
別段使わなくてもいいような、そんな気のするステートメント達ですね。
使いどころ
全体的な話をするといらない子扱いしてしまいましたが、
ピンポイントで向いている処理というのはあります。
例えば「フォルダ内のすべてのファイルを処理」するときに、
Dim 処理ファイル名 As String 処理ファイル名 = Dir("○○フォルダ\売上データ(*).xlsx") Do While 処理ファイル名 <> "" Workbooks.Open ("○○フォルダ\" & 処理ファイル名) ~開いたブックへの処理~ 処理ファイル名 = Dir() Loop
と書くことができます。
「ファイルがなくなると""を返すDirの性質」を、
Do While Dirの結果 <> ""
と書くことで、
「Dir関数がファイル名を返している間はループを続ける」
というのを表現しています。
こういう定型化されたコードではたまに出てきますので、
読むためにも知っておく必要はあるでしょう。
ただ、じゃあこれをDo~Loop文で書くとどうかというと…
Dim 処理ファイル名 As String 処理ファイル名 = Dir("保存フォルダ\売上データ*.xlsx") Do Workbooks.Open ("処理フォルダ\" & 処理ファイル名) ~開いたブックへの処理~ 処理ファイル名 = Dir() If 処理ファイル名 = "" Then Exit Do Loop
うーん、やっぱりこっちがわかりやすいですね(笑)
慣れてる方には、ちょっと冗長なのでしょうけど。
なぜDo~Loop文が分かりやすいのかというと、
- 最初のファイルを取得
- そのファイルを開いて処理
- 次のファイルを探す
- あればLoop、無ければExit
のように、その自由度を活かして時系列順に書くことができるからです。
今回の例では、ループの最後の部分にIf文を書くことで、
続けるか?終わるか?を最後に判定できるため、読みやすくなっています。
対して、Do While/Untilはループの開始時に条件を書くしかないため、
慣れないうちはループがどう終わるかのイメージがしづらい傾向があります。
ということで、繰り返しになりますが、
- 基本Forで書けるように頑張ってみて、
- 無理ならDo~Loop文で書く
という使い分けをまずは身に着けましょう。
WhileやUntilの条件でループを離脱するのではなく、
「If 条件 Then Eixt Do」できっちりと離脱する場所を明示した方が、
ループ処理が身に着くのも早いんじゃないかと思います。
おまけ:初めから条件を満たさない場合
補足になりますが、Do While/Until文は、
「最初から条件を満たしていない場合は、ループに入らない」
という特徴があります。
先ほどの「フォルダ内のファイルをループ」について、
Dim 処理ファイル名 As String 処理ファイル名 = Dir("保存フォルダ\売上データ*.xlsx")
このループに入る前の時点でファイルがなく、Dirが最初から""を返した場合に、
Do While 処理ファイル名 <> "" Workbooks.Open ("処理フォルダ\" & 処理ファイル名) ' ↑実行されないためエラーは出ない
Do Workbooks.Open ("処理フォルダ\" & 処理ファイル名) ' ↑実行されてしまい、エラーになる
という違いがあります。
ただ、これを利点と言っていいかは正直疑問で、個人的には、
「通過するのに一度も処理されないループブロックは書くべきではない」
と思っています。
今回の場合は、
Dim 処理ファイル名 As String 処理ファイル名 = Dir("保存フォルダ\売上データ*.xlsx") If 処理ファイル名 = "" Then MsgBox("処理対象のファイルがひとつもありませんでした。") Exit Sub End If Do Workbooks.Open ("処理フォルダ\" & 処理ファイル名) ~~
と書いた方が絶対に読みやすいですよね?
「ループの繰り返し条件をスタートから満たしていない」というのはかなり大事な例外でしょうから、キッチリIf文で分けて準備段階で処理し、必要ならそこでExitするべきです。
片づけられるものはしっかり片付けてから、
本題に集中できるメインコードを書くよう心がけましょう。