在Excel VBA中需要用循环去遍历某些参数时,就会考虑到VBA中常见的四种循环方法:For…next, For each …next, Do…loop,While…wend。一般情况下,四种方法是等效的,可以互相替换使用,但是在使用的便利性上,上述方法各有优势。
接下来逐个解析四种方法的特点。
1>For…next
先看一下它的用法:
For 计数器 = Start to End [ 步长 ]
[ statements ]
[ Exit for ]
[ statements ]
Next [ 计数器 ]
For…Next 语句的语法包含以下部分:
计数器 必填。 用作循环计数器的数值变量。 该变量不能是布尔值或数组元素。
start 必填。 counter 的初始值。
end 必填。 counter 的最终值。
步长 可选。 counter 每次通过循环时更改的量。 如果不指定,step 默认为 1。
statements 可选。 For 和 Next 之间执行指定次数的一个或多个语句。
解释一下上述用法,开始指的是循环开始的值,结束指的是循环结束的值,实质上就是计数器值的一个值域,如果计数器的值在值域内,就执行循环语句,计数器每运行到Next,就增加一个步长(不指定默认为1),可以为负数。
我们先来看一些实例。
Case1:计算1+2+3+…+98+99+100的和。
Sub Sumdemo1()
Dim num%, I% '定义数据类型
num = 0
I = 1
For I = 1 To 100 'I是计数器,值域是1到100,默认步长是1
num = num + I '求和
Next I 'I这步可省略,经过一次步长+1
MsgBox num '对话框显示求和结果
End Sub
运行上述代码,可以得到如下图所示的结果。
上述代码是一个比较经典的循环的例子,利用步长的变化求和,延伸至可以等差求和。
接下来看另一个经典的例子。
Case2:在Excel里生成九九乘法表。
Sub testdemo2()
Dim num1%, num2% '定义变量类型
For num1 = 1 To 9
For num2 = 1 To 9
If num2 > num1 Then '九九乘法表是左下三角形,必须行>列
Exit For
Else
Cells(num1, num2) = num2 & "x" & num1 & "=" & num1 * num2 '将字符和数值写入单元格
End If
Next num2
Next num1
End Sub
运行上述代码,可以得到如下图所示的结果。
上述代码进行了嵌套循环,从而进行二维方向的遍历,在实际的使用中,嵌套循环使用的几率比较高,"九九乘法表"这个例子值得学习和理解。
结合For…next的用法和两个例子,可以发现它适用于已知范围数字循环,这种循环是以一定的次数来执行语句的。
2>For each … next
同理,先看一下它的用法:
For each Element in Collection
[statements]
[ Exit for ]
[ statements ]
Next Element
Element 必填。 用作循环计数器的数值变量。
Collection 必填。一组变量的集合或者数组。
statements 可选。 For each和 Next 之间执行指定次数的一个或多个语句。
在使用这个方法时,由于循环里面有Each Element的存在,因此需要锚定一个范围或者组群Collection,即对象,并用一个变量去表示它,通过next逐步遍历里面的元素。接下来看一下实例。
Case3:显示当前工作簿的所有工作表的名称。
Sub testdemo1()
Dim ws As Worksheet '定义变量类型
For Each ws In Worksheets '遍历工作表
MsgBox ws.Name '显示当前的工作表名称
Next ws
End Sub
运行上述代码,可以得到如下图所示的结果。
由于当前的工作簿只有一张工作表,因此循环进行了一次就结束了。上述例子中,ws就是已知类型的变量,表示Each Element,去遍历Collection即worksheets,并将工作表的名称显示出来。
Case4:计算表格所示8位业务员的提成金额。
Sub testdemo2()
Dim rng As Range '定义变量类型
For Each rng In Range("b2:b9") '遍历range("b2:b9"),多个工作表应指明具体worksheet
rng.Offset(0, 1) = rng.Value * 0.1 '计算结果放在变量的右侧一列c列
Next rng
End Sub
运行上述代码结果如下:
Case4的代码中rng,range(“b2:b9”)分别代表Each Element和Collection,遍历一次就计算当前变量的提成。
结合For each…next的用法和案例,可以发现这种循环主要针对集合或数组进行操作,让所用元素执行一次循环语句。
3>Do…loop
同理,先看一下它的用法:
Do while Condition
[statements]
[exit do]
[statements]
Loop
Condition 必填。 计算结果为“True”或“False”的数值表达式或字符串表达式。 如果条件 为 Null,则条件 被视为 False。
statements 可选。 Do 和 Loop 之间执行指定次数的一个或多个语句。
在执行这个循环语句时,首先先判断条件,如果是True,即满足condition的条件,就执行后面的statement代码,执行循环,直到循环结束,否则跳出循环,执行loop后的代码,所以想要实现遍历的目的,条件设置非常重要(避免进入死循环)。
Case5:计算1+2+3+…+98+99+100的和。
Sub testdemo_1()
Dim num%,I% '定义变量类型
num = 0: I = 1
Do while I <= 100 '先判断条件,true则进入循环
num = num + I '求和
I=I+1 '每个变量的迭代
Loop
msgbox num
End Sub
运行代码可以得到和case1图示一样的结果。关于Do…loop还有另外一种形式,case5的代码还可以写成下述这种类型,结果也是一样的。
Sub testdemo_2()
Dim num%,I% '定义变量类型
num = 0: I = 1
Do
num = num + I '求和
I=I+1 '每个变量的迭代
Loop while I <=100 '先进入循环,再判断条件
msgbox num
End Sub
Case5的Do…loop采用了case1的例子,不同遍历方法得到了相同的结果,说明在某些案例中与for…next可以互相替换使用,另外case5的两种实现方法是while关键字在不同位置,即在进入循环前检查条件(testdemo_1)和在至少运行循环一次后检查条件(testdemo_2)。
此外,while关键字还可以与until关键字替换使用,不过此时case5 testdemo_1中的Do while I <= 100要改成Do until I > 100,
case5 testdemo_2中的Loop while I <=100要改成Loop while I >100。
无论是While还是until,都可以顺利得到结果,但是值得注意的是,对于while(until)在后的循环在条件为 False 时仍继续运行,此时在Do while(until)和loop while(until)两种方式执行的次数是不同的。
Case6:计算Case4中8位业务员的提成金额。
Sub testdemo_3()
Dim num%,n% '定义变量类型
n = 1
Do
n = n + 1
If Cells(n, "A") = "" Then '条件判断
Exit Do '条件成立退出循环
Else
Cells(n, "C") = Cells(n, "B") * 0.1 '计算提成
End If
Loop
End Sub
上述代码也可以得到case4图示的结果。在这个实例中,增加了退出Do…loop的Exit Do,此时如果将判断条件交给IF…else…end if,则循环中while(until)也可以省略,Do…loop只是执行循环不进行判断。
Do…loop的用法和实例表明,如果事先只知道判断的条件,循环内容和次数不确定,那么可以设置合适的条件采取这种循环。
3>While…Wend
同上,先看一下它的用法:
While Condition
[statements]
[exit do]
[statements]
Wend
Condition 必填。 计算结果为“True”或“False”的数值表达式或字符串表达式。 如果条件 为 Null,则条件 被视为 False。
statements 可选。条件为“True”时执行的一个或多个语句
在执行这个循环语句时,如果条件 为“True”,则将执行所有语句,直至遇到“Wend”语句,则重复该过程,知道不满足条件,退出循环。While…Wend循环可嵌套到任何级别。
Case7:计算1+2+3+…+98+99+100的和。
Sub testdemo_1()
Dim num%, I% '定义变量类型
num = 0: I = 1
While I <= 100 '条件判断
num = num + I '求和
I = I + 1 '每个变量的迭代
Wend
MsgBox num
End Sub
该实例计算结果也是同上。接着看下一个例子。
Case8:找出D列平均成绩的最大值。
Sub testdemo_2()
Dim i%, MaxValue! '定义变量类型
i = 2
While i <= 6 '条件判断
If Range("d" & i) > MaxValue Then
MaxValue = Range("d" & i) '变量的迭代
End If
i = i + 1
Wend
MsgBox "成绩的最大值是: " & MaxValue
End Sub
这个实例是在D列逐个循环判断大于变量MaxValue的值,并将最大值赋给MaxValue。循环的逻辑和前述的例子一样,但是在While…wend里面嵌套了一个if逻辑判断,组合使用比较灵活。
While…wend循环与Do while…loop循环非常相似,但是while…wend不能用exit do退出循环,而且执行时优先执行循环体后进行判断。
综上分析,总结一下四种循环结构的特点:
循环结构 | 特点 |
---|---|
For…next | 适用于已知范围数字循环 |
For each …next | 主要针对集合或数组 |
Do…loop | 事先只知道判断的条件,循环内容和次数不确定 |
While…wend | 同Do…loop |