|

楼主 |
发表于 2009-7-25 21:04
|
显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件 ★ 免费下载 ★ ★ 使用帮助★
使用Excel的内置函数
对于要实现的某一功能,如果有Excel的内置函数能够实现,那么就用Excel的内置函数,不需要另外自定义函数,因为自定义的函数总比Excel内置的函数慢。
考虑在VBA代码中使用工作表函数
操作单元格区域的Excel工作表函数通常比完成同样任务的VBA程序更快(但不能确保总是这样,您可以对它们进行速度测试)
例如,在代码中使用SUM工作表函数比用VBA代码在单元格区域中循环并相加值要快得多,以此为例,下面的代码运行速度相对较慢。
Sub AddItSlow()
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
'为了进行测试,我们循环5次
Dim N As Long
For N = 1 To 5
'***************************
Dim Cell As Range
For Each Cell In Worksheets(2).Range("A1:G200")
[a1] = [a1] + Cell.Value
Next Cell
'***************************
Next N
'--------------------------------------
Finish = Timer
MsgBox "本次运行的时间是" & Finish - Start
End Sub
下面的代码实现相同的功能,但运行得更快(几乎瞬间完成)。
Sub AddItFaster()
'快近600倍
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
'为了进行测试,我们循环5次
Dim N As Long
For N = 1 To 5
'***************************
[a1] = Application.WorksheetFunction. _
Sum(Worksheets(2).Range("A1:G200"))
'***************************
Next
'--------------------------------------
Finish = Timer
MsgBox "本次运行的时间是" & Finish - Start
End Sub
产生统计结果的函数(例如PRODUCT、COUNT、COUNTA和COUNTIF)是代替运行速度更慢的VBA代码的很好的选择,并且,一些工作表函数(例如MATCH和LOOKUP)能够将单元格区域作为参数。
不要认为工作表函数总是更快的
如下例所示,在VBA中没有Max或Min函数,但Excel中有该函数。于是,您能编写出如下代码:
Sub MaxIt1()
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
'为了测试,我们循环10000次
Dim N As Long
For N = 1 To 10000
'***************************
[J1] = Application.Max([J2], [J3])
'***************************
Next N
'--------------------------------------
Finish = Timer
MsgBox "本次运行时间是" & Finish - Start
End Sub
或者,您能在VBA中使用下面的方式实现相同的功能:
Sub MaxIt2()
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
'为了测试,我们循环10000次
Dim N As Long
For N = 1 To 10000
'***************************
If [J2] >= [J3] Then [J1] = [J2] Else [J1] = [J3]
'***************************
Next N
'--------------------------------------
Finish = Timer
MsgBox "本次运行的时间是" & Finish - Start
End Sub
比较上面的两个程序,可能认为使用工作表函数会更快,但事实上用VBA代码可以获得几乎相同的速度。因此,在一些大的循环中,您可以对实现同样功能的工作表函数的VBA代码进行测试。一些内置的VBA函数事实上运行速度也是慢的,因此,在编写代码时,在不同方式之间进行速度测试总是值得的。
但是,在代码中经常使用的简单的函数,就直接编写代码,而不是使用WorksheetFunction对象。
使用Range.SpecialCells()来缩小需要处理的单元格数。
只要有可能就使用集合索引值
您能在集合中使用名称或者数字来指定某个单一的对象,但使用对象的索引值通常是更快的。如果您使用对象的名字,VBA必须解析名字成为索引值;但如果您使用索引值,就能避免这个额外的步骤。
但另一方面,我们要注意到在集合中通过名称指定对象有很多优点。使用对象名称能使您的代码更容易阅读和调试。此外,通过名称指定一个对象比通过索引值更安全,因为当您的代码运行时该对象的索引值可能变化。
例如,某菜单的索引值表示它在菜单栏中的位置,但是如果在菜单栏中添加了菜单或者删除了菜单,该菜单的索引值会变化。这样,您就不应该考虑代码的速度,而应保证代码运行可靠。您使用索引值加快代码速度之前,应该确保该索引值在代码运行过程中或使用应用程序时不会改变。
使用完全受限制的对象引用
使用完全受限制的对象引用消除了引用模糊并确保变量有明确的类型。
一个完全受限制的对象引用包括了对象库名称,如下代码所示:
Dim wb As Excel.Workbook
如果您使用通用的对象数据类型声明变量和参数,在运行过程中VBA可能必须对它们的引用进行解析为(某对象的)属性和方法,这将导致速度变慢。
一个通用对象数据类型示例如下:
Dim wb As Workbook
使用已有的VBA方法
也有一些特定目的的VBA方法,它们提供在单元格区域执行特定操作的一种简单的方式。例如工作表函数,这些特定的方法比使用通常的VBA编码完成相同的任务要更快。最常用的是”Replace”方法和”Find”方法。
Replace方法:
下面的示例用了一种相当慢的方式代码改变单元格区域H1:H20000中每个单元格的值。
Sub NowDoThis1()
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
Dim Cell As Range
For Each Cell In Worksheets(1).Range("H1:H20000").Cells
If Cell.Value = 4 Then Cell.Value = 4.5
Next
'--------------------------------------
Finish = Timer
MsgBox "本次运行的时间是" & Finish - Start
End Sub
下面的示例使用Replace方法进行同样的操作,但运行得更快。
Sub NowDoThis2()
'快约两倍
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
Worksheets(1).Range("H1:H20000").Replace "4", "4.5"
'--------------------------------------
Finish = Timer
MsgBox "本次运行的时间是" & Finish - Start
End Sub
Find方法:
下面的代码使用一种相对较慢的方法在单元格区域I1:I5000中值为4的单元格内添加一个蓝色的椭圆。
Sub FindItSlow()
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
Dim Cell As Range
For Each Cell In Worksheets(1).Range("I1:I5000").Cells
If Cell.Value = 4 Then
With Worksheets(1).Ovals.Add(Cell.Left, _
Cell.Top, Cell.Width, _
Cell.Height)
.Interior.Pattern = xlNone
.Border.ColorIndex = 5
End With
End If
Next
'--------------------------------------
Finish = Timer
MsgBox "本次运行的时间是" & Finish - Start
End Sub
下面的示例使用了Find方法和FindNext方法执行相同的任务,但运行速度更快。
Sub FindItFaster()
'快约25倍
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
Dim Cell As Range, FirstAddress As String
With Worksheets(1).Range("I1:I5000")
Set Cell = .Find(4)
If Not Cell Is Nothing Then
FirstAddress = Cell.Address
Do
With Worksheets(1).Ovals.Add(Cell.Left, _
Cell.Top, Cell.Width, _
Cell.Height)
.Interior.Pattern = xlNone
.Border.ColorIndex = 5
End With
Set Cell = .FindNext(Cell)
Loop Until Cell Is Nothing Or Cell.Address = FirstAddress
End If
End With
'--------------------------------------
Finish = Timer
MsgBox "本次运行的时间是" & Finish - Start
End Sub
关于带有特定目的的VBA方法的更多的信息,您可参见VBA帮助系统相关主题。
结语
当然,代码优化可能不是绝对必要的,这依赖于您要做的工作……如果您正好编写了一个快速且简短的或者是一次性使用且与速度和/或简洁要求无关的代码,您就不需要优化代码。
但另一方面,如果您处理一个带有很多数据、工作簿、工作表等大的工程,再次检查您第一次编写好的代码,看看是否您的代码需要优化,而这样做总是值得的。
最终,您将养成编写代码的好习惯,将会使您的代码更简洁、运行更快速、并且容易为您自已和他人阅读和调试。同时,由于您的代码简洁,因而输入更快,工作效率更高。 |
|