繰り返し処理(ループ)を行うためのステートメントである、
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 = 10 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文を使います。
この点、Do While/Untilって中途半端なんですよね。
For文ほど読みやすく簡潔には書けませんし、
その割にはDo~Loop文ほど自由がききません。
このDo~Loop文の自在さで、Do While/Until文は完全に再現することができ、
Do While R <= 10 ' ↓ 書き換え Do If (R < = 10) = False Then Exit Do
Do Until R > 10 ' ↓ 書き換え Do If R > 10 Then Exit Do
という対応になります。
ほんのちょっとコードは長いですが、ループ処理に慣れていない方にとっては、
書き換えた方が断然わかりやすいですよね。
Do~Loopで繰り返し、If~Exit Doで抜けるのがはっきり明示されている方が、
かなり理解しやすいのではないでしょうか。
特に「Do While/Untilの判定は各ループの開始時」という仕様が明確でないのが、
学び始めに理解を妨げる原因になっているような気がします。
逆に言えば、Do While/Until文は、
「Doの直後にIf ~ Exit Doを書く場合は、While/Untilでそれを省略できますよ」
という、ただ短く書くためだけのステートメントとも言えます。
そして、ただ短く書くだけならForさんが最強ですからね。
続行/離脱の条件が1ヵ所にしか書けず、しかも判定タイミングも開始時に固定なため、
- Do~Loop文なら書けるけど、Do While~Loop文だと難しい
- Do While文で書けるような処理なら、For文で書いた方が読みやすい
という状況に陥りやすいです。
既存のマクロを読むために必要なので、存在を知っておく意味はあると思いますが、
別段使わなくてもいいような、そんな気のするステートメント達ですね。
使いどころ
全体的な話をするといらない子扱いしてしまいましたが、
ピンポイントで向いている処理というのはあります。
例えば「フォルダ内のすべてのファイルを処理」するときに、
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
のように、その自由度を活かして時系列順に書くことができるからです。
Do While/Untilはループの開始時に条件を書くしかなく、判定もそこでしかできないので、慣れないうちは処理の流れをイメージしづらいのです。
Do While文と、Do Until文が、
- For文ほど読みやすく簡潔に書けません。
- その割にはDo~Loop文ほど自由がききません。
と感じる理由はなんとなく伝わったでしょうか。
ループ処理に慣れていない方は、
Do~Loop文の中で、丁寧にIf~Exit Doを書いた方が読みやすいと思います。
Do Whileをスラスラ読めるレベルの方も、たった十数文字程度の差なら、
のちに引き継ぐかもしれない後輩のためにも、
Do~Loop文で書いてあげることをおすすめします。
おまけ:初めから条件を満たさない場合
補足になりますが、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するべきです。
片づけられるものはしっかり片付けてから、
本題に集中できるメインコードを書くよう心がけましょう。