Excel 中用 VBA 字典尋找代替 VLOOKUP

來源:互聯網
上載者:User

標籤:style   blog   http   color   使用   os   

從上一篇《PYTHON操作EXCEL》可以看到,Python 操作 Excel 已非常自如方便。但是 Python 和相關庫畢竟是一個額外的依賴,若能從 Excel 自身解決此類問題,自然是更為易用。
1. VBA 中的雜湊表 用 Python 的著眼點主要是 VLOOKUP 公式太慢了,所以關鍵是要找到一種更高效的演算法或資料結構定位元據。VLOOKUP 要求對列進行排序,內部應該是對列內資料進行二分尋找,演算法上不好再最佳化了,那就只好更換一種資料結構。搜尋了一下,VBA 提供了 Scripting.Dictionary 這一詞典結構,而且有文章說內部是雜湊表實現,那就正是我要的東西了。
這樣,VLOOKUP(lookup_value,table_array,col_index_num,range_lookup) 這一公式就轉為下面的詞典尋找方式來實現:
  • 使用要從中進行尋找的 table_array 內容構建詞典。用 table_array 第一列作為 key,table_array 第 col_index_num 列作為 value,插入 Dictionary 中:Dictionary.Add key, value;
  • 尋找時只需直接取 Dictionary 內的值 Dictionary.Item(lookup_value),即可完成尋找;
若是僅僅 VLOOKUP 一次,倒也不必費勁先建立起一個詞典。但當使用同樣 VLOOKUP 公式的儲存格很多時(比如幾萬個),就顯得其必要了。因為 Dictionary 只需要建立一次,就可以用 O(1) 的複雜度進行多次尋找了。
2. VLOOKUP 慢,主要問題不在演算法上 從演算法角度,詞典尋找的確快於二分尋找,但優勢並不是那麼明顯。所以在具體執行時,我發現使用詞典尋找的 VBA 宏運行速度並不比 VLOOKUP 快多少,運行時 Excel 仍然會導致系統假死幾個小時。按說如此簡單的程式不應該那麼慢,問題究竟在哪裡呢?
經過一段摸索,我才發現問題的根源所在:
  • VBA 往 Excel 表格中填內容時,會引發表格中已有公式的自動計算,非常耗時;
  • Excel 表格內容更新時,會觸發螢幕顯示內容的自動重新整理,代價也很高;
所以提高 VBA 指令碼執行效能的關鍵點,在於計算時關掉公式自動計算和螢幕重新整理,這也是我始料未及的。在 VBA 中實現這兩點很容易,但由於 VLOOKUP 本身即是公式,我沒能想通直接調用 VLOOKUP 時如何避免這兩點帶來的效能損失。
3. 樣本 VBA 代碼 在做了上面提到的兩次最佳化之後,原來 VLOOKUP N 個小時才能完成的任務,只用了 7 秒鐘就執行結束了。

下面是我寫的一段範例程式碼。我不熟悉 VBA 語言,只是照葫蘆畫瓢。代碼規範程度相差甚遠,但題意應是體現其中了。有心的朋友可以用作參考。

Sub 在機器表上產生一級分中心()‘‘ 在機器表上產生一級分中心 Macro‘Application.Calculation = xlCalculationManualApplication.ScreenUpdating = Falset0 = Timer‘ 詞典Set map_dict = CreateObject("Scripting.Dictionary")‘ 開啟分中心映射表Set map_sheet = Worksheets("分中心映射表")map_nrows = map_sheet.Range("A300").End(xlUp).RowSet my_rows = map_sheet.Range("A2:B" & map_nrows).Rows‘ 遍曆分中心映射表,獲得 分中心 對應的一級分中心,插入詞典For Each my_row In my_rows   center = my_row.Cells(1, 1).Value   city = my_row.Cells(1, 2).Value   If Not map_dict.Exists(center) Then       map_dict.Add center, city   End IfNext my_row‘ 開啟機器表Set dispatch_sheet = Worksheets("機器表")dispatch_nrows = dispatch_sheet.Range("a99999").End(xlUp).RowSet my_rows = dispatch_sheet.Range("a1:b" & dispatch_nrows).Rows‘ 遍曆開通表,通過詞典獲得 machine_id 對應的一級分中心,插入開通表For Each o_row In my_rows   center = o_row.Cells(1, 2).Value   o_row.Cells(1, 2).Value = map_dict.Item(center)Next o_rowMsgBox "在機器表上產生一級分中心。共處理 " & dispatch_nrows & " 條記錄,總耗時" & Timer - t0 & "秒。"‘ 銷毀建立的詞典Set map_dict = Nothing‘ 開啟自動計算和螢幕重新整理Application.Calculation = xlCalculationAutomaticApplication.ScreenUpdating = True‘End Sub
最後補充一點:我先實現的詞典尋找,後發現效能問題根源,所以未能去比較 VLOOKUP 與詞典尋找兩種方式的具體效能差異。我想如果差異可以忍受,那麼直接在 VBA 中調用 VLOOKUP 公式或許是一種更為簡單的實現。 4. 測試案例

上面的代碼如何測試呢?

id  name:分中心映射表,字典表    nickName id:機器表,待匹配表           匹配後結果:1    a1                              b1    1                              b1    a12    a2                              b2    2                              b2    a23    a3                              b3    3                              b3    a34    a4                              b4    4                              b4    a45    a5                              b5    5                              b5    a56    a6                              b6    6                              b6    a67    a7                              b7    7                              b7    a78    a8                              b8    8                              b8    a89    a9                              b9    9                              b9    a910   a10                             b10   10                             b10   a10

— EOF —

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.