現在、入門書を画面で確認しながら
ExcelVBAの勉強をしています。
Do...Loopで躓いてしまいました。
Do...Loopステートメントの種類は
条件を満たすまでループするもの
Do Until...Loop(ループの前で条件判断)
Do...Loop Until(ループの後で条件判断)
条件を満たす間はループするもの
Do While...Loop(ループの前で条件判断)
Do...Loop While(ループの後で条件判断)
とあって、
例えば、A1からA7まで文字が入力されていて
空白のセルになるまで太文字にするとしたら、
ループの前に条件判断していると
A1が空白だと処理はされず
ループの後で条件判断すると
A1が空白でも処理はされる
とありました。
とすると、
条件判断はループ後にした方が良いと言う事なのでしょうか。
(空白でも処理してくれるので)
自分が処理したいものが
ループ「後」にするのか又は
ループ「前」にするのか
どのように判断すれば良いのかと言うことと、
また、
条件を満たすUntil(まで)とWhile(間)
どちらを使用すれば良いのかの判断方法もわかりません。
超初心者の質問内容で申し訳ありません。
VBAって面白いなぁと思い始めたところで
なんとか理解したいので
教えていただけると大変助かります。
よろしくお願いします。
No.1
- 回答日時:
参考にしてください。
Sub ボタン1_Click()
GYOU =1
Do While Cells(GYOU, 1) <> ""
Cells(GYOU, 2).Value = 1
GYOU = GYOU + 1
Loop
End Sub
Sub ボタン2_Click()
GYOU = 1
Do Until Cells(GYOU, 1) = ""
Cells(GYOU, 2).Value = 2
GYOU = GYOU + 1
Loop
End Sub
Sub ボタン3_Click()
GYOU = 1
Do
Cells(GYOU, 2).Value = 3
GYOU = GYOU + 1
Loop While Cells(GYOU, 1) <> ""
End Sub
Sub ボタン4_Click()
GYOU = 1
Do
Cells(GYOU, 2).Value = 4
GYOU = GYOU + 1
Loop Until Cells(GYOU, 1) = ""
End Sub
結局、どれでも出来ました。自分で、得意にする分だけマスターしても十分です。
諸先輩が作られたマクロがあれば、それを継承したほうが良いでしょう。
N88-Basicからの方は、For Nextよく使われますよね。
ちなみに、私は、古くからデータベース関係のプログラム作っていました為か
Do While で済ましています。
風邪で寝込んでしまって
せっかく皆さんに回答していただいたのに
すぐにお返事ができませんでした。
申し訳ありませんでした。
hallo-2007さんの書いてくださったコードを
動きを見てみると
前に条件があるもの(上から2つめまで)は
A1が空白だと、B1には、数値が入らないけれど
空白でなければ、同じ結果が出るのだから
わざわざ「空白」だったらなどと考えなければ
自分の好きなものを使えば良いのですね。
ありがとうございました。
No.2
- 回答日時:
どの形式を使うかは、状況によって異なりますが、
「後」判断では、必ず一回はループに入ります。
「前」判断は、条件によってはループを素通りさせたいときに使います。
「Until」か「While」かは、何とも言えません。
これに関しては、「こういうときに使う」というより、
「何を、どう判断するか」と「どうしたいのか」で決まります。
「Whike X <= Y」は「Until X > Y」と同義なので、
「While」でも「Until」でも同じ結果を得ることは可能ですから...
この回答への補足
お返事が遅れてしまって申し訳ありませんでした。
回答ありがとうございました。
1つ確認させていただきたいのは、
「ループを素通りさせたい」場合というのは
どのようなケースなのでしょうか。
No.3
- 回答日時:
こんばんは。
私は、いつも不思議に感じるのは、入門者の多くは、なぜか、Do Loop を使うのが多いかなっていうことです。練習でやっている分には別に悪くはないけれども、
For i = xx To yy よりも、
圧倒的に使う頻度は少ないです。
使い方も、ワンランク難しいし、離脱条件がはたしてあっているのか、明確に判定できないことがあります。
>条件を満たすUntil(まで)とWhile(間)
>どちらを使用すれば良いのかの判断方法もわかりません。
どちらでもよいというよりは、その終了条件、または、継続条件が正しく書けるなら、ということです。では、その判定は先か後かですが、多くは、後のほうが多いです。(最後のコードのSample2/3 を参照してください。)古くから書いている人には、コードとしては、While のほうがなじみあるはずです。
また、私たち、日本人は、日本語的な発想をするので、条件文の論理式は、肯定形では間違いが少ないのですが、否定形になると論理積が反転して、論理和になったりしますので、間違えが多くなります。
空白の判定を、セルで取らざるを得ないですが、ループのたびに、セルの判定をするというのは、あまりうまいコードだとは言えません。
私の挙げた「For i=xx To yy」方法は、本来は、ループの最終行は予め決めておくだけで済みますので、その後のことは考える必要がありません。
# 例えば、A1からA7まで文字が入力されていて
#空白のセルになるまで太文字にするとしたら
Sub TestSample1()
Dim i As Long
Dim j As Long
'最終行を取る
j = Range("A65536").End(xlUp).Row
For i = 1 To j '最終行まで
Cells(i, 1).Font.Bold = True 'セルの書式の変更
Next i
End Sub
VBAを多く扱っている人は、こういうスタイルの書き方になります。それは、セル・オブジェクトのアクセス回数を減らすという、VBAの原則があるのです。
Do Loop で、Cells の判定をしてしまうと、二重のアクセスになってしまいます。
上記の場合は、A1 が、空白の場合はどうするか、それはなんともいえませんが、無視しても動きます。
例えば、
しかし、こんな判定条件を入れたりします。
If Cells(i, 1).Value ="" Then
Cells(i, 1).Font.Bold = True
End If
とかしますが、なくてもとまってしまうということはありません。
なお、Value プロパティは、習慣的に入れたほうがよいです。
入れない場合は、暗黙値として、Value値が返ることにはなっているのですが、返らない場合があります。
Cells(i, 1).Value =""
少し、VBAを勉強すると、="" の判定というのは、間が抜けて見えるかもしれませんが、通常は、これでよいです。IsEmpty という関数がありますが、本来、ワークシート上のセルの判定には、IsEmpty はあまり使いません。
なお、1行目が空白の場合は、以下のTestSample2の場合は、このままでは、回避しようがありません。では、行数ですればよいと思いますが、その都度、セルの行数を取って、判定するコードというのも、あまり賢い方法とは言えません。セルは、Rangeオブジェクトといって、かなりいろいろなプロパティを持っています。その中で必要な値を選ぶという作業を持たされます。そうすると、その作業分のロスが多くなるのです。
'前か後か
・1行目が空白なら、これは、通らない
Sub TestSample2()
Dim i As Long
i = 1
Do While Cells(i, 1).Value <> "" 'セルの判定
Cells(i, 1).Font.Bold = True 'セルの書式の変更
i = i + 1
Loop
End Sub
・1行目が空白でも、こちらは通る
・というよりは、1回目は判定されていないからです。
Sub TestSample3()
Dim i As Long
i = 1
Do
Cells(i, 1).Font.Bold = True
i = i + 1
Loop While Cells(i, 1).Value <> ""
End Sub
いろいろ研究してみてください。
この回答への補足
遅くなり、大変すいませんでした。
回答していただいてありがとうございました。
入門書に
「Do...Loopは必ずマスターしてください」などと
書かれているので、「あぁ、そう言うものなんだ」と思っていました。
>「For i=xx To yy」方法は、
本来は、ループの最終行は予め決めておくだけで済みますので、
その後のことは考える必要がありません。
その後のこととは
For...Next,For Each ...Nextの方が
セル・オブジェクトのアクセス回数を減らすので
メモリやコードの量が軽減できる?とかでしょうか。
>Do Loop で、Cells の判定をしてしまうと、二重のアクセス
ごめんさい。この部分がちょっとわからなくて。。
もし、
Do...Loopを使用するなら
Untilより後条件のWhileの方が使いやすいというイメージですが
これも解釈違いかもしれないので、
たくさん書いていただいたのに
意味がピンと来ず申しわけないのですが、
もう少し教えていただければと思います。
No.4
- 回答日時:
> For i = xx To yy よりも、圧倒的に使う頻度は少ないです。
Accessなどでは、
。
・
RecSet.Open
Do Until RecSet.EOF
・
・
・
RecSet.MoveNext
Loop
などは、ごく一般的に使います。
判断条件は数値だけとは限らないので...
No.5
- 回答日時:
#3 の回答者です。
私が書いているのは、あくまでも、Excelの話です。VBA全体的にみても、For i =xx To yy の方が頻繁に出てくるし、扱いが楽です。もともと、インクリメンタルな処理が可能な場合は、数値で行うのが一般的です。数値処理できないものに、For i= xx To yy は、最終値の判定は不可能です。それは、言うまでもありません。
私の書いた
「 For i = xx To yy よりも、
圧倒的に使う頻度は少ないです。」というのは、
その後に、良く読んでいただければ分かる話ですが、Cellsの判定条件として、Cellsの引数に代入する数値によって、直接、Rangeオブジェクトを取得しています。ExcelのVBAでは、ワークシートのRangeオブジェクトに頻繁にアクセスすることを嫌います。Excel VBAでは、他にも方法はありますが、この種のLoop の離脱判定は、Do ~ Loop は、ほとんど使いません。
単独でオブジェクト等を取得している場合は、この限りではありません。例えば、Open For Input やDir関数では、Do ~ Loop は使います。その理由は、すでにオブジェクトを取得しているからですが、また、逆に数値的な取得が不可能だからです。この種の使い方は、レベルとしては、一段階上になります。
No.6
- 回答日時:
> 「ループを素通りさせたい」場合というのは
> どのようなケースなのでしょうか。
またまた、Accessの例で恐縮ですが、(エクセルではあまり無いのかも知れませんが)
データベースのテーブル内の特定の条件を満たすレコードに対しして処理を行いたい場合、
Accessでは、その条件を満たレコードセットを作って、ここからレコード読み込みます。
このとき、条件によっては、レコードが一つもない場合もあり得ますから、このレコードセットを開くといきなりEOF(End Of File)となります。
このときは処理させたくないわけですから、
Do Until RecSet.EOF
・
※特定の条件に合致したレコードに対する処理
・
Loop
は素通りとなります。
なお、「レコード」はエクセルでの「行」をイメージしていただければ良いでしょう。
再度、お返事が遅れてしまい申し訳ありませんでした。
実は、VBA以外であればExcelよりAccessの方が
馴染みがあるので
(Excelの方が需要が多くてExcelVBAを選択しました)
イメージがつかめました。
ありがとうございました。
No.7ベストアンサー
- 回答日時:
こんにちは。
#3 の回答者です。
>「Do...Loopは必ずマスターしてください」などと
>書かれているので、「あぁ、そう言うものなんだ」と思っていました。
テレビの高校講座『情報』で、ロボットを制御する場合に出てくるコードなどでは、Do ... Loop とか、While ... Wend という方法が出てきます。ただし、VB系に似ていて別のものです。昔は、そうだったのかもしれません。マスターするというのは、たぶん、プログラム言語としては、避けられないのかって思うのですが、Excel VBAの場合は、それが出てくるのは、なかなか先のことのような気がします。
年間、数百のコードを自分なりに書いているのに、時々、Do ... Loop は、自分で新しいパターンを作る場合は、丁寧に気をつけないと、「無限ループ」に陥ります。単純なものならともかく、少し込み入った条件になると、While ... や Until ... の後に書く条件は、かなり注意が必要なのです。Excelの場合は、複合条件が発生することがたまにあるからです。それは、よほどなれているつもりでも、ミスることがあります。
しかし、にも関わらず、Excelに関しては、使う方法が決まってしまっているように思います。そんなに多いパターンがありません。それは、追々、学んでいったらよいし、一旦、それが決まってしまったら、他に覚える必要はあまり出てこないのです。
たぶん、他のVBAのベテランの方も同様だとは思うのですが、この方法は、全部、パターン化してしまって、「こういう時にはこれしかない」というもので、定石のようなものがあるような気がします。Excel上のパターンで一番多いのは、Find メソッド(検索)です。これは、ヘルプに決まったパターンが出てきますから、それを写せばよいです。
他は、Dir 関数、Open For Input メソッド、また、#4 さんの示した、ADO等(実は、Excelでも出てくるし、避けられない方法です)、かなり上級の部類に入ってきます。
>For...Next,For Each ...Nextの方が
>セル・オブジェクトのアクセス回数を減らすので
>メモリやコードの量が軽減できる?とかでしょうか。
コードの量自体は、多少、減る程度です。メモリに関しては分かりません。
古い人は、VBAやVBのことをスクリプト言語だと揶揄する人がいますが、この種の言語は、実際にコードは見かけ上、上から下に動いていきます。その時に、手間の掛かるものが多ければ多いほど、実行速度は落ちてきます。
>>Do Loop で、Cells の判定をしてしまうと、二重のアクセス
>ごめんさい。この部分がちょっとわからなくて。。
Cells というのは、Range オブジェクトで、それを判定するには、それを取得しなければなりません。入門編では、Range("A1").Select, Cells(1,1).Select と書きます。
また、Cells(1,1).Value = ""
とすると、VBAでは、Cells(1,1) または、Range("A1")というオブジェクトにアクセスして、そのValue プロパティの判定をします。
(つけなくても、暗黙的に、Value プロパティが取得できます)
以下をもう一度みてください。
Sub TestSample2()
Dim i As Long
i = 1
Do While Cells(i, 1).Value <> "" 'セルを取得してチェックし
Cells(i, 1).Font.Bold = True 'もう一度、セルを取得して、セルのFontプロパティの変更 をしています。
i = i + 1
Loop
End Sub
つまり、100セルあれば、100 * 2 = 200 回になっているということになりますね。
-----------------------
こちらの場合は、
Sub TestSample1()
Dim i As Long
Dim j As Long
'最終行を取る
j = Range("A65536").End(xlUp).Row '一度取って、変数jというメモリに入れている。
For i = 1 To j '最終行まで
Cells(i, 1).Font.Bold = True 'セルの書式の変更 (各セル1度)
Next i
End Sub
Range("A65536").End(xlUp).Row で、最後の行を取ってしまっています。
こちらの場合は、100 セルあれば、100 +1 = 101 になっています。
セルの状態によってその処理の仕方が変わる場合は、その回数は増えますが、それでも、少ないはずです。
----------------------
ただし、他の方に突っ込まれるかもしれませんから、これ以外にも、このような方法があります。Range("A1", Range("A65536").End(xlUp)) で、オブジェクトとして取得してしまっているので、その中から、小出しに、オブジェクトを切り出して、変数 c に入れて、処理しています。他にも、Excelには、Excel独特の方法がありますが、それは割愛しておきます。
Dim c As Range 'Variant でも可
For Each c In Range("A1", Range("A65536").End(xlUp))
c.Font.Bold = True
Next c
これで、何が違うかというと、速さが違ってきます。(わずかな違いですけれども)
メモリの使用量は、私には良く分かりません。減らして使うように考えろとは言われますが、実際に、普段、それほど大きなコードを書くことは少ないのです。例えば、変数で、Variant 型よりも、Range型、もしくは、文字列型、数値型と、それぞれを明確に使い分けるとかは言います。それによって、メモリの変化は、明確には出てこないけれど、処理スピードには影響を受けるとは言います。しかし、時間経過とともにExcel全体のメモリ量が徐々に増えていくことのほうが気になることが多いです。
参考:「MSDN」
http://msdn.microsoft.com/library/ja/default.asp …
今回の内容には、直接関係ありませんが、
「Office TANAKA VBA高速化テクニック」
(なお、内容は、実験的なものですから、そのコード自体がこうでなくてはならないというものではありません。)
http://officetanaka.net/excel/vba/speed/index.htm
Wendy02さん、
再度詳しく教えていただいてありがとうございました。
実は、あれからExcelVBAのサンプル集のような本を購入して
Do...Loopが使われているコードを試そうとしたのですが
60例の中で、Do...Loopのサンプルコードが少なく
殆どがFor...Next,For Each ...Nextだったのです。
前回の使用頻度について書かれていたことに
少しだけ実感したような気がします。
なので、入門者の段階ではループの上限のあるForNextを練習して
慣れたら、無限ループの回避方法など勉強して
Do...Loopにトライするつもりです。
たくさん、お勉強させていただきました。
ありがとうございました。
No.8
- 回答日時:
こんばんは、No1です。
Do~Loop For~Nextは、使い方は理解できましたか。
以下は、中級、上級者の為ですので今の時点で必要ではないかもしれませんが、簡単な実験してみましたのでご紹介いたします。
購入された本ではD0~Loopの使い方の事例に、
Do While ActiveCell.Value <> ""
ActiveCell.Offset(0, 4).Value = 5
ActiveCell.Offset(1, 0).Activate
Loop
セルを下方向へ1行づつアクティブにして、アクティブなセルが空白かどうかで、Loopを終了するかどうか、判断させます。
エクセルVBAの入門では、結構紹介されているようですが、実は、実用ではあまり良い式ではありません。
以下の4つのマクロを試してみてください(最初はMacro1を)
1行目に開始時間、2行目に終了時間がでるようにしました。
1~3行目は、表示形式をユーザー定義でhh.mm.ss.00とでもしておいてください。処理にかかった時間がわかると思います。
Sub Macro1()
Range("A1").Value = [=NOW()]
For i = 4 To 60000
Cells(i, 1).Value = 1
Next
Range("A2").Value = [=NOW()]
End Sub
Sub Macro3()
Range("B1").Value = [=NOW()]
i = 4
Do While i <= 60000
Cells(i, 2).Value = 2
i = i + 1
Loop
Range("B2").Value = [=NOW()]
End Sub
Sub Macro3()
Range("C1").Value = [=NOW()]
i = 4
Do While Cells(i, 1) <> ""
Cells(i, 3).Value = 3
i = i + 1
Loop
Range("C2").Value = [=NOW()]
End Sub
Sub Macro5()
Range("D1").Value = [=NOW()]
Cells(4, 1).Activate
Do While ActiveCell.Value <> ""
ActiveCell.Offset(0, 4).Value = 5
ActiveCell.Offset(1, 0).Activate
Loop
Range("D2").Value = [=NOW()]
End Sub
今の時点では、難しいこと考えず繰り返し処理の書き方を理解してもらえばよいと思います。職場などで実践の場合は、当然取り扱うデータの数、マクロの実行頻度など状況に応じて色々テクニック覚えていくことになると思いますので、その時にデータの状況など記載して質問してみれば別途アイディア紹介してもらえると思います。
追記
最初に紹介したマクロで、途中に空白入れた場合以外に、最初に空白入れた場合の実行内容も参考になるかと思います。
がんばってください。
hallo-2007さん、
再度ありがとうございました。
おかげで
同じ条件でも処理時間が違うことを目で確認できました。
>難しいこと考えず繰り返し処理の書き方を理解してもらえばよいと思います
そうですね。理屈を追求しようとすると先へなかなか進めないので
簡単なコードをとにかく数多く書く練習をして
慣れたいと思います。
今回、こちらに質問させていただいてから
VBAを以前より意識するようになりました。
ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) ExcelVBAでDo Until loopのネスト、IF文を使って一致する物と一致しない物としたい 11 2022/12/24 17:46
- Excel(エクセル) Excelにて、フォルダ内のTextファイルをマクロで統合すると文字化けしてしまう時の解消コード 4 2023/01/01 07:32
- Excel(エクセル) Excel VBAどこが間違ってますか? 4 2023/07/17 10:04
- Visual Basic(VBA) 【VBA】印刷マクロのループ処理が反映されません 3 2022/08/09 02:15
- Java Java 南京錠 2 2023/02/04 11:46
- C言語・C++・C# TCP/IP通信時のサーバーからの受信 2 2022/11/23 09:11
- Visual Basic(VBA) VBAのユーザーフォームのテキストボックスに入力制限をしたい 6 2022/11/15 08:28
- Excel(エクセル) beforecloseの中からの抜け出し方 1 2023/08/10 18:01
- Visual Basic(VBA) エクセル VBA 条件付き書式 簡略化したい 2 2022/06/02 17:46
- Visual Basic(VBA) 前回ご教授いただいたコードに覚えたてのループ処理で品名りんごAから順に20回for nextでループ 7 2023/01/13 22:01
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
IF関数で空欄("")の時、Null...
-
関数TRANSPOSEで空白セルを0に...
-
数式による空白を無視して最終...
-
Excelで"0"を空白に変換する方法
-
Excel:関数が入っているセルに...
-
空白セル内の数式を残したまま...
-
Excel > ピボットテーブル「(空...
-
OpenOfficeでのワイルドカード...
-
Excel 特定セルの数値を参照し...
-
エクセルで、「複数のセルの中...
-
vlookup にて、返す値が、空白...
-
VLOOK関数で作った請求書で、¥...
-
リンクされているセルを空白と...
-
エクセルで上の行の値を自動的...
-
エクセルで、合計をもとめたい...
-
エクセルの数式で教えてください。
-
時間の差し引き 元セルが空白セル
-
【EXCEL】空白でないセルの位置...
-
Excel関数 直近3回分の出庫平均...
-
列の複数ある空白セルを飛ばし...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
IF関数で空欄("")の時、Null...
-
数式による空白を無視して最終...
-
エクセルでCSVを編集するとき、...
-
ピボットテーブルで空白セルの...
-
excel2010 空白セルにのみ貼り...
-
Excel > ピボットテーブル「(空...
-
空白セル内の数式を残したまま...
-
「データ要素を線で結ぶ」がチ...
-
エクセルで、「複数のセルの中...
-
Excelで、入力文字の後に自動で...
-
エクセル 連番が途切れていると...
-
《Excel2000》SUMPRODUCT関数で...
-
SUMIFS関数で「計算式による空...
-
【Excel】 csvの作成時、空白セ...
-
形式貼り付けの「空白を無視す...
-
Excel:関数が入っているセルに...
-
リンク先が空白若しくはゼロの...
-
エクセルで上の行の値を自動的...
-
エクセルにて負の時間を0:00と...
-
エクセルのグラフで式や文字列...
おすすめ情報