亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 辦公 > Excel > 正文

編寫高效Excel VBA代碼的最佳實踐(二)

2024-08-23 19:48:28
字體:
來源:轉載
供稿:網友

盡可能少使用“.”,使用對象變量
在前面已經介紹過的對長對象引用使用對象變量以及使用With…End With等都是簡化”.”的方法。因為在代碼中的每個句點都表示至少一個(而且可能是多個)過程調用,而這些過程調用必須在后臺執行。真正好的做法是在局部進行緩存對象引用,例如,應該把對象模型中較高層次的對象引用保存到局部對象變量中,然后用這些對象引用創建其他較低層次的對象引用。例如,引用某單元格數據時,可用如下代碼:

Dim i As Long
For i=1 to 10
Workbooks("Book1.xls").Worksheets("Sheet1").Cells(1,i).Value=i
Next i

但下面的代碼運行效率更高,因為代碼中引用Workbook對象和Worksheet對象的調用命令只執行一次,而上面的代碼中卻要執行10次。

Dim ws As Worksheet
Dim i As Long
Set ws= Workbooks("Book1.xls").Worksheets("Sheet1")
For i=1 to 10
ws.Cells(1,i).Value=i
Next i

當您一遍又一遍的使用相同對象引用時,您可以將該對象引用設置成一個變量,然后使用該變量代替對象引用。這樣,您在代碼中只需對該對象變量進行引用即可。
例如,下面的示例在每行中調用Workbook對象的Sheets屬性、Range屬性和Value屬性三次,當您循環1000次時,總共要調用屬性6000次。

Sub DoThis1()
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
Dim N As Long
For N = 1 To 1000
Workbooks("Book1").Sheets(1).Range("c5").Value = 10
Workbooks("Book1").Sheets(1).Range("d10").Value = 12
Next
'--------------------------------------
Finish = Timer
MsgBox "本次運行的時間是" & Finish - Start
End Sub

您能在循環開始前通過設置Workbooks(“Book1”).Sheets(1)作為一個對象變量來優化上面的例子,下面的示例在每行僅調用一個Range屬性,當循環1000次時,總共只調用該屬性2000次。
注意,“Value”是一個缺省屬性,通常不需要明確指定它,它將被自動調用。因此,該屬性在下面的代碼中被忽略。然而,就養成良好的編程習慣而言,還是建議您最好寫明該屬性。

Sub DoThis2()
'快約35%以上
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
Dim ThisBookSheet As Object, N As Long
Set ThisBookSheet = Workbooks("Book1").Sheets(1)
For N = 1 To 1000
ThisBookSheet.Range("c5") = 10
ThisBookSheet.Range("d10") = 12
Next
'--------------------------------------
Finish = Timer
MsgBox "本次運行的時間是" & Finish - Start
End Sub

您可以比較這兩個示例的運行速度,它們都得到同樣的結果,但在我的機子上運行時,第二個示例比第一個快60%。當然,您還能使用With…End With語句獲得相同的結果。
您也能不設置明確的對象變量,而是使用With語句減少對象的重復引用。上面的示例也能使用下面的代碼,該代碼僅調用Workbooks屬性和Sheets屬性一次,當循環1000次時,總共調用1000次屬性。

Sub DoThis3()
'快約35%以上
Dim Start As Double, Finish As Double
Start = Timer
'--------------------------------------
Dim N As Long
With Workbooks("Book1").Sheets(1)
For N = 1 To 1000
.Range("c5") = 10
.Range("d10") = 12
Next
End With
'--------------------------------------
Finish = Timer
MsgBox "本次運行的時間是" & Finish - Start
End Sub

上述三個示例均得到相同的結果,但在我的機子上運行時,本示例比第一個示例快50%以上。

在一個語句中進行復制或者粘貼
在用宏錄制代碼時,首先是選擇一個區域,然后再執行ActiveSheet.Paste。在使用Copy方法時,可以在一個語句中指定復制的內容及要復制到的目的地。
例如,將B5:C6區域的內容復制到以單元格B8開始的區域中,使用宏錄制器的代碼為:

Range("B5:C6").Select
Selection.Copy
Range("B8").Select
ActiveSheet.Paste

經修改后的最佳代碼是:

Range("B5:C6").Copy Destination:=Range("B8")

合理地使用消息框和窗體
在一個很長的程序中,嘗試著將消息框或者窗體安排顯示在程序的最開始或最后面,避免干擾用戶。此外,盡管窗體提供了許多功能,但它們能夠導致文件大小迅速增加。還有就是盡量避免給工作表單元格鏈接用戶窗體控件,因為這樣將會導致鏈接更新操作,影響程序運行速度。
盡可能加速對數字的運算
(1)當對整數進行除法時,您可以使用整型除法運算符(/)而不是浮點除法運算符(/),因為無論參與除法運算的數值類型如何,浮點除法運算符總會返回Double類型的值。
(2)在任何具有整數值的算術表達式中使用Single或Double值時,整數均將被轉換成Single或Double值,最后的結果將是Single或Double值。如果要對作為算術運算結果的數字執行多次操作,可能需要明確地將該數字轉換為較小的數據類型。
提高字符串操作的性能
(1)盡可能少使用連接操作。可以在等號左邊使用Mid函數替換字符串中的字符,而不是將它們連接在一起。使用 Mid 函數的缺點是替換字符串必須與要替換的子字符串的長度相同。例如,

Dim strText As String
strText = "this is a test"
Mid(strText, 11, 4) = "tent"

(2)VBA提供許多可用來替換函數調用的內部字符串常量。例如,可以使用vbCrLf常量來表示字符串中的回車/換行組合,而不是使用Chr(13) & Chr(10)。
(3)字符串比較操作的執行速度很慢。有時,可以通過將字符串中的字符轉換為 ANSI 值來避免這些操作。例如,下列代碼會檢查字符串中的第一個字符是否為空格:

If Asc(strText) = 32 Then

上面的代碼會比以下代碼更快:

If Left(strText, 1) = " " Then

使用Asc()檢驗ANSI的值
在VBA中,可以使用Chr$()函數把數轉換成字符,并確定ANSI的值,但是更好的是使用Asc()函數把字符串轉換成數值,然后確定它的ANSI值。如果需要進行有限次數的這種檢驗,對程序代碼的效率可能不會產生很大影響,但是,如果需要在多個循環內進行這種檢驗時,這將節省處理時間并且有助于程序代碼更快地執行。
使用Len()檢驗空串
盡管有多種方法可檢驗空串,但首選的是使用Len()函數。為了測試零長度的串,可以選擇把串與””相比較,或者比較串的長度是否為0,但這些方法比用Len()函數要用更多的執行時間。當對字符串應用Len()函數并且函數返回0值時,說明該字符串是空的或者是零長度的字符串。
并且,因為在If語句內非零值被認為是True,所以直接使用Len()函數而不必與””或0比較,減少了處理時間,因此執行更快。
有效地使用數組
用VBA數組而不是單元格區域來處理數據,即可以先將數據寫入到某個數組,然后用一個語句就可以將數組中的數據傳遞到單元格區域中。(前文已述)
在創建已知元素的確定數組時,使用Array函數對于節約空間和時間以及寫出更具效率的代碼是非常理想的。例如,
http://www.49028c.com/
Dim Names As Variant
Names=Array("Fan","Yang","Wu","Shen")

此外,應該盡量使用固定大小的數組。如果確實選擇使用了動態數組,應該避免數組每增加一個元素就改變一次數組的大小,最好是每次增加一定數量的元素。

使用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幫助系統相關主題。

結語
當然,代碼優化可能不是絕對必要的,這依賴于您要做的工作……如果您正好編寫了一個快速且簡短的或者是一次性使用且與速度和/或簡潔要求無關的代碼,您就不需要優化代碼。
但另一方面,如果您處理一個帶有很多數據、工作簿、工作表等大的工程,再次檢查您第一次編寫好的代碼,看看是否您的代碼需要優化,而這樣做總是值得的。
最終,您將養成編寫代碼的好習慣,將會使您的代碼更簡潔、運行更快速、并且容易為您自已和他人閱讀和調試。同時,由于您的代碼簡潔,因而輸入更快,工作效率更高。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
5252色成人免费视频| 尤物精品国产第一福利三区| 国产日韩精品在线观看| 日韩欧美精品免费在线| 精品久久久久国产| 日韩经典中文字幕在线观看| 久久91亚洲精品中文字幕奶水| 18久久久久久| 国产日韩中文在线| 亚洲国产精品女人久久久| 欧美电影院免费观看| 精品视频www| 欧美乱人伦中文字幕在线| 亚洲性xxxx| 欧美日韩亚洲一区二| 亚洲欧洲激情在线| 欧美成人免费小视频| 久久久噜噜噜久久久| 国产一区二区在线免费| 日韩欧美国产激情| 欧美专区在线观看| 日韩中文字幕在线免费观看| 这里只有精品丝袜| 色先锋资源久久综合5566| 欧美日韩亚洲国产一区| 日韩视频免费大全中文字幕| 精品国内产的精品视频在线观看| 久久人人爽人人爽人人片av高请| 久久偷看各类女兵18女厕嘘嘘| 久久久久久久成人| 欧美色道久久88综合亚洲精品| 高潮白浆女日韩av免费看| 日本欧美国产在线| 国内精品久久久久伊人av| 97视频在线播放| 中文字幕av日韩| 日韩在线国产精品| 国产精品高清在线观看| 国产主播喷水一区二区| 亚洲欧美一区二区三区情侣bbw| 这里只有精品丝袜| 91tv亚洲精品香蕉国产一区7ujn| 久久的精品视频| 国产精品美女999| 国产精品自产拍高潮在线观看| 成人av.网址在线网站| 亚洲精品综合久久中文字幕| 国产日韩在线看片| 91日本在线观看| 国产一区二区欧美日韩| 国产一区二区三区在线看| 青草青草久热精品视频在线观看| 欧美大片免费看| 欧美日韩国产一区二区三区| 国产欧美一区二区三区久久人妖| 青青草99啪国产免费| 欧美大片在线免费观看| 777国产偷窥盗摄精品视频| 亚洲欧美日韩天堂| 日韩中文字幕免费视频| 国产精品第一视频| 国内免费精品永久在线视频| 深夜福利亚洲导航| 久久久久久久一区二区| 日韩人体视频一二区| 丰满岳妇乱一区二区三区| 欧美电影免费在线观看| 国产精品久久久久免费a∨大胸| 日韩最新av在线| 亚洲iv一区二区三区| 日韩精品免费综合视频在线播放| 国产视频久久久久| 国产精品一区二区电影| 91中文字幕在线| 久久久久国产精品免费网站| 国产日韩欧美中文在线播放| 欧美性色视频在线| 国产在线观看精品一区二区三区| 中日韩美女免费视频网址在线观看| 亚洲成人中文字幕| 性欧美长视频免费观看不卡| 亚洲天堂av图片| 精品在线观看国产| 成人国产亚洲精品a区天堂华泰| 日本欧美黄网站| 亚洲护士老师的毛茸茸最新章节| 清纯唯美亚洲综合| 亚洲国产精品免费| 欧美性xxxxhd| 久久国产精品视频| 国产+成+人+亚洲欧洲| 亚洲综合大片69999| 亚洲a在线播放| 欧美最猛黑人xxxx黑人猛叫黄| 国产精品美女免费视频| www日韩欧美| 欧美日韩国产123| 夜夜嗨av一区二区三区免费区| 亚洲精品美女久久久久| 欧美成人免费小视频| 亚洲乱码av中文一区二区| 动漫精品一区二区| 黑人与娇小精品av专区| 美日韩在线视频| 国产精品爱久久久久久久| 欧美超级乱淫片喷水| 色偷偷偷综合中文字幕;dd| 欧美视频13p| 欧美最猛性xxxx| 欧美精品videos另类日本| 激情成人中文字幕| 日韩av123| 欧美性猛交xxxx乱大交蜜桃| 亚洲色图狂野欧美| 欧美床上激情在线观看| 国产成人福利视频| 亚洲丁香婷深爱综合| 成人黄色短视频在线观看| 亚洲а∨天堂久久精品喷水| 成人午夜高潮视频| 成人444kkkk在线观看| 中文字幕不卡在线视频极品| 国产精品91免费在线| 成人国产精品色哟哟| 欧美亚洲日本网站| 日韩欧美成人精品| 日韩av有码在线| 92裸体在线视频网站| 国产综合视频在线观看| 欧美激情一区二区三区成人| 国产精品揄拍一区二区| 亚洲日韩欧美视频| 国产v综合v亚洲欧美久久| 97久久精品人人澡人人爽缅北| 国外成人免费在线播放| 爱福利视频一区| 青青精品视频播放| 日韩欧美亚洲一二三区| 国产精品扒开腿做| 一本色道久久88亚洲综合88| 亚洲国产一区自拍| 亚洲色图第三页| 国产精品日日摸夜夜添夜夜av| 亚洲欧美国产另类| 国产午夜精品一区二区三区| 91久久精品美女| 国内精品久久久久| 亚洲性日韩精品一区二区| 夜夜躁日日躁狠狠久久88av| 国产精品永久免费在线| 日韩av在线天堂网| 亚洲аv电影天堂网| 久久精品91久久香蕉加勒比| 日本精品久久电影| 亚洲精品日韩久久久| 91国内揄拍国内精品对白| 日韩黄色高清视频| 日韩电影在线观看中文字幕| 亚洲精品免费一区二区三区| 91精品久久久久久久久久另类| 色与欲影视天天看综合网| 国产精品综合久久久| 美女黄色丝袜一区| 久久精品中文字幕免费mv|