掌握了Excel中最常见的range对象的属性和方法过后,再利用上VBA里的判断和循环控制结构语句,我们就可以自己慢慢解决一些小的需求了。
今天A哥就带大家从实例出发,来把我们之前学习的知识给串起来。
案例:删除零值单元格所在行,在一个range区域,如果有任何一个单元格的值为零值,则删除本行。数据大家可以自行举例,可以使用rand函数配合int函数来随机生成含有零值的区域。
在解决实际需求前,我们都需要拟定大体的思路。对于这个问题,我们很直观的可以想到:遍历每一个单元格,判断如果是零的话,就删除行。
那么,我们可以写这样一个程序:
Sub delete_zero()Dim Rng As RangeDim i%, j%, Row_Num%, Col_Num%Row_Num = Range('a1').CurrentRegion.Rows.CountCol_Num = Range('a1').CurrentRegion.Columns.CountFor i = 1 To Row_Num For j = 1 To Col_Num If Cells(i, j).Value = 0 Then Cells(i, j).EntireRow.Delete Exit For End If NextNextEnd Sub
个中的逻辑也很简单,利用i循环行,j循环列。如果单元格的数值为0,那么就删除这行,并不再执行列的循环,跳出来继续执行行的循环。
看起来不错,运行一下看看吧!
F5结果执行如下图
等等,怎么里面还有零?
我们的逻辑似乎没有问题,但我们在执行过程中没有考虑excel删除行的执行方式问题。一般来说,执行行删除操作,下面的行会自动上移。因此,执行过一次行删除之后,每一行的行号相对于原始表已经发生了变化,自然会漏删一些行。
解决方法很简单,只要把行的循环进行倒序删除就可以。
Sub delete_zero()Dim Rng As RangeDim i%, j%, Row_Num%, Col_Num%Row_Num = Range('a1').CurrentRegion.Rows.CountCol_Num = Range('a1').CurrentRegion.Columns.CountFor i = Row_Num To 1 Step -1 For j = 1 To Col_Num If Cells(i, j).Value = 0 Then Cells(i, j).EntireRow.Delete Exit For End If NextNextEnd Sub
F5运行看看,结果里面还有0吗?
这个需求的解决,到这里,似乎是结束了,然而并没有。我们刚才处理的是很小一部分数值,这种循环方式速度也还可以,但如果是大量数据,例如1000 行呢?
我们用上述方式,对1000 行数据进行了处理,处理时间为0.71秒,如果是处理10000条数据岂不是要更长?
有没有更快的运行方式呢?
我们再仔细观察一下上面的代码,我们发现,Excel每发现一行,就要执行一次删除操作,这会相当浪费时间。可不可以一次性把发现的单元格都删除呢?
这就要用到我们之前将的union方法了。
修改后的代码如下:
Sub delete_zero_new()Dim Rng As RangeDim i%, j%, Row_Num%, Col_Num%Row_Num = Range('a1').CurrentRegion.Rows.CountCol_Num = Range('a1').CurrentRegion.Columns.CountFor i = Row_Num To 1 Step -1 For j = 1 To Col_Num If Cells(i, j).Value = 0 Then If Rng Is Nothing Then Set Rng = Cells(i, j) Else Set Rng = Union(Rng, Cells(i, j)) End If Exit For End If NextNextRng.EntireRow.DeleteSet Rng = NothingEnd Sub
这里要注意的是object的使用。
一定要用set来给object赋值。例如这里,如果只写rng=cells(i,j),像函数那样赋值,则会出现对象错误报错。要改成 set rng =rn
在判断是否为nothing的时候需要用is,而不是用=。
改进了代码之后,F5运行程序只需要0.32秒,是不是比之前快了很多?
根据以上这个案例,我们可以直观的得到一个经验:在处理大量数据的时候,要尽量减少excel的固有操作,如select, activate, delete等等,这样可以大大提高运行速度。
总结一下:
使用for来遍历所有单元格
使用一次性excel操作,避免多次重复操作
掌握了Excel中最常见的range对象的属性和方法过后,再利用上VBA里的判断和循环控制结构语句,我们就可以自己慢慢解决一些小的需求了。
今天A哥就带大家从实例出发,来把我们之前学习的知识给串起来。
案例:删除零值单元格所在行,在一个range区域,如果有任何一个单元格的值为零值,则删除本行。数据大家可以自行举例,可以使用rand函数配合int函数来随机生成含有零值的区域。
在解决实际需求前,我们都需要拟定大体的思路。对于这个问题,我们很直观的可以想到:遍历每一个单元格,判断如果是零的话,就删除行。
那么,我们可以写这样一个程序:
Sub delete_zero()Dim Rng As RangeDim i%, j%, Row_Num%, Col_Num%Row_Num = Range('a1').CurrentRegion.Rows.CountCol_Num = Range('a1').CurrentRegion.Columns.CountFor i = 1 To Row_Num For j = 1 To Col_Num If Cells(i, j).Value = 0 Then Cells(i, j).EntireRow.Delete Exit For End If NextNextEnd Sub
个中的逻辑也很简单,利用i循环行,j循环列。如果单元格的数值为0,那么就删除这行,并不再执行列的循环,跳出来继续执行行的循环。
看起来不错,运行一下看看吧!
F5结果执行如下图
等等,怎么里面还有零?
我们的逻辑似乎没有问题,但我们在执行过程中没有考虑excel删除行的执行方式问题。一般来说,执行行删除操作,下面的行会自动上移。因此,执行过一次行删除之后,每一行的行号相对于原始表已经发生了变化,自然会漏删一些行。
解决方法很简单,只要把行的循环进行倒序删除就可以。
Sub delete_zero()Dim Rng As RangeDim i%, j%, Row_Num%, Col_Num%Row_Num = Range('a1').CurrentRegion.Rows.CountCol_Num = Range('a1').CurrentRegion.Columns.CountFor i = Row_Num To 1 Step -1 For j = 1 To Col_Num If Cells(i, j).Value = 0 Then Cells(i, j).EntireRow.Delete Exit For End If NextNextEnd Sub
F5运行看看,结果里面还有0吗?
这个需求的解决,到这里,似乎是结束了,然而并没有。我们刚才处理的是很小一部分数值,这种循环方式速度也还可以,但如果是大量数据,例如1000 行呢?
我们用上述方式,对1000 行数据进行了处理,处理时间为0.71秒,如果是处理10000条数据岂不是要更长?
有没有更快的运行方式呢?
我们再仔细观察一下上面的代码,我们发现,Excel每发现一行,就要执行一次删除操作,这会相当浪费时间。可不可以一次性把发现的单元格都删除呢?
这就要用到我们之前将的union方法了。
修改后的代码如下:
Sub delete_zero_new()Dim Rng As RangeDim i%, j%, Row_Num%, Col_Num%Row_Num = Range('a1').CurrentRegion.Rows.CountCol_Num = Range('a1').CurrentRegion.Columns.CountFor i = Row_Num To 1 Step -1 For j = 1 To Col_Num If Cells(i, j).Value = 0 Then If Rng Is Nothing Then Set Rng = Cells(i, j) Else Set Rng = Union(Rng, Cells(i, j)) End If Exit For End If NextNextRng.EntireRow.DeleteSet Rng = NothingEnd Sub
这里要注意的是object的使用。
一定要用set来给object赋值。例如这里,如果只写rng=cells(i,j),像函数那样赋值,则会出现对象错误报错。要改成 set rng =rn
在判断是否为nothing的时候需要用is,而不是用=。
改进了代码之后,F5运行程序只需要0.32秒,是不是比之前快了很多?
根据以上这个案例,我们可以直观的得到一个经验:在处理大量数据的时候,要尽量减少excel的固有操作,如select, activate, delete等等,这样可以大大提高运行速度。
总结一下:
使用for来遍历所有单元格
使用一次性excel操作,避免多次重复操作