电竞比分网-中国电竞赛事及体育赛事平台

分享

看完這篇,如果你還不懂VBA字典,那我就沒(méi)辦法了

 5jia5 2020-04-13
作者:看見(jiàn)星光
 微博:EXCELers / 知識(shí)星球:Excel

HI,大家好,我是星光。在Excel基礎(chǔ)教程里,咱們講過(guò)函數(shù)+透視表是普通表格用戶處理數(shù)據(jù)的最佳組合,函數(shù)用于數(shù)據(jù)清洗整理,透視表用于數(shù)據(jù)匯總分析。如果你接觸過(guò)Power BI,會(huì)發(fā)現(xiàn)類似的情況,PowerQuery用于數(shù)據(jù)清洗整理,PowerPivot用于數(shù)據(jù)匯總分析。而VBA編程呢?也不例外,數(shù)組用于數(shù)據(jù)清洗整理,字典用于數(shù)據(jù)匯總分析……關(guān)于數(shù)組,可以看「零基礎(chǔ)學(xué)VBA編程系列教程」中的數(shù)組四篇,關(guān)于字典——打個(gè)響指,今天就來(lái)給大家講下什么是字典。

前方高能預(yù)警,本文共分8節(jié),建議先收后看。

目錄如下▼

1 什么是字典

2 如何創(chuàng)建字典

3 如何將數(shù)據(jù)存入字典

4 如何將數(shù)據(jù)從字典取出

5 如何移除字典元素

6 如何遍歷字典元素

7 如何釋放字典

8 思考和其它

……



1 丨

什么是字典


談到字典,有些朋友可能會(huì)想到新華字典、康熙字典、英漢字典、有道字典等等。我今天說(shuō)的字典,和這些家伙——都沒(méi)關(guān)系。字典(Dictionary)是VBA編程中的一個(gè)對(duì)象,具有操作簡(jiǎn)單、運(yùn)行高效的特點(diǎn),常用于數(shù)據(jù)的條件查詢、聚合匯總等。如果說(shuō)數(shù)組是VBA處理數(shù)據(jù)的基礎(chǔ)結(jié)構(gòu),那么字典就可以被稱為核心。攤手,騙你娶你,不論男女。

我舉個(gè)例子。

如上圖所示的數(shù)據(jù)表,如果我們需要查詢看見(jiàn)星光的特長(zhǎng),數(shù)組的解法步驟如下▼

首先將數(shù)據(jù)源存入數(shù)組,然后遍歷姓名,第1個(gè)人名不是,第2個(gè)人名不是,第3個(gè)人名不是,第4個(gè)還不是……一直到第7個(gè)人名才是,于是取特長(zhǎng),退出數(shù)組循環(huán)……

數(shù)組循環(huán)是線性查找的方式,只能一個(gè)個(gè)元素找過(guò)去,如果查找值過(guò)多,效率就很不理想。

如果是用字典呢?

首先將數(shù)據(jù)源裝入字典,然后用一句代碼就可以查詢相關(guān)人名的特長(zhǎng)了。

比如查詢看見(jiàn)星光的特長(zhǎng)..▼


字典('看見(jiàn)星光')

不用懷疑,不用循環(huán),就是這么簡(jiǎn)單。

……

還記得嗎?在數(shù)組四篇之什么是數(shù)組里,咱們講過(guò)數(shù)組處理數(shù)據(jù)的過(guò)程可以分為5步。創(chuàng)建數(shù)組->將數(shù)據(jù)存入數(shù)組->數(shù)組運(yùn)算->將數(shù)組數(shù)據(jù)寫入Excel->釋放數(shù)組。

字典處理數(shù)據(jù)的過(guò)程與數(shù)組十分相似:創(chuàng)建字典->將數(shù)據(jù)裝入字典->將數(shù)據(jù)從字典取出->釋放字典。

——那么如何創(chuàng)建字典?

2 丨

如何創(chuàng)建字典



如上文所講,字典(Dictionary)是VBA編程的一個(gè)對(duì)象,但它并非VBA自帶的妻妾,而是集成在動(dòng)態(tài)鏈接庫(kù)文件Scrrun.dll中,需要綁定文件后才能夠使用。綁定文件有兩種方式,前期綁定和后期綁定。

聽(tīng)起來(lái)很麻煩的樣子,但操作起來(lái)其實(shí)——很簡(jiǎn)單。

先來(lái)說(shuō)前期綁定。

操作步驟如下▼

在VBE編輯器的[工具]選項(xiàng)卡下,單擊[引用],在打開(kāi)的[引用]對(duì)話框中勾選'Microsoft Scripting Runtim'選項(xiàng),單擊[確定]按鈕,關(guān)閉對(duì)話框即可。


通過(guò)'前期綁定'的方式引用Scrrun.dll文件后,即可在VBA代碼中利用Dim語(yǔ)句聲明變量為字典對(duì)象,然后使用字典處理數(shù)據(jù)。

示例代碼如下..▼




Sub 前期綁定()    Dim d As New Dictionary '聲明一個(gè)字典對(duì)象    ……End Sub

第2句代碼聲明一個(gè)字典對(duì)象,其名為d。語(yǔ)法格式如下▼


Dim 變量名 As New Dictionary

……

然后再說(shuō)下后期綁定。

所謂后期綁定是指通過(guò)CreateObject函數(shù)創(chuàng)建對(duì)字典對(duì)象的引用,示例代碼如下▼






Sub 后期綁定()    Dim d As Object '聲明一個(gè)對(duì)象    Set d = CreateObject('scripting.dictionary') '創(chuàng)建對(duì)字典的引用    ……End Sub


第2句代碼聲明一個(gè)對(duì)象類型的變量,其名為d。

第3句代碼使用CreateObject函數(shù)創(chuàng)建對(duì)字典對(duì)象的引用……

……

那么前期綁定和后期綁定有什么不同呢?

有朋友說(shuō),星光你是不是個(gè)鐵憨憨?很明顯,前期綁定需要手動(dòng)操作,后期綁定用代碼就行了!——拜托,我五行多金,你可以說(shuō)我憨,但不能帶鐵。而且,攤手,事情可沒(méi)有這么簡(jiǎn)單▼

比如——在使用前期綁定后,編寫代碼時(shí)系統(tǒng)會(huì)自動(dòng)顯示字典的成員列表,而后期綁定不會(huì)顯示;有些屬性,前期綁定是支持的,但后期綁定不能使用(詳情見(jiàn)文末說(shuō)明);另外,通常前期綁定的代碼運(yùn)算效率要比后期快一些。

但是——前期綁定的代碼不適合發(fā)送給其它用戶使用,畢竟其它用戶未必會(huì)去手動(dòng)綁定字典對(duì)象;因此后期綁定的方式兼容性更強(qiáng)些。

總結(jié)——建議編寫代碼時(shí)采用前期綁定,編寫完成后,如需發(fā)送他人使用,再改為后期綁定,如此魚和熊掌必可兼得矣~


3 丨

如何將數(shù)據(jù)裝入字典



創(chuàng)建完字典后,我們需要將數(shù)據(jù)裝入字典。但在講如何將數(shù)據(jù)裝入字典前,需要先給大家說(shuō)一下字典的結(jié)構(gòu)。

從表格角度,通俗而言,字典是有兩個(gè)一維數(shù)組或者說(shuō)兩列數(shù)據(jù)構(gòu)成的特殊表。第1列是關(guān)鍵字,被稱為Key;第2列是每個(gè)關(guān)鍵字對(duì)應(yīng)的條目,被稱為Item。其中每個(gè)關(guān)鍵字在字典中都是唯一的,不會(huì)也不允許出現(xiàn)重復(fù)值。


和數(shù)組所不同的是,字典的行數(shù)看起來(lái)并不固定,你往字典里裝了多少個(gè)關(guān)鍵字,它就會(huì)有幾行數(shù)據(jù),每一行數(shù)據(jù)都由兩列組成,第1列是關(guān)鍵字,第2列是關(guān)鍵字對(duì)應(yīng)的條目。

那么如何將數(shù)據(jù)裝入字典呢?

直接賦值就可以了。語(yǔ)法格式如下▼


字典(關(guān)鍵字)=條目

舉個(gè)例子。






Sub 字典添加數(shù)據(jù)()    Dim d As New Dictionary '聲明一個(gè)字典對(duì)象    d('看見(jiàn)星光') = 99    d('Excel星球') = 98End Sub

第2行代碼使用前期綁定的方式聲明一個(gè)字典對(duì)象,其名為d。

第3行代碼將關(guān)鍵字'看見(jiàn)星光'裝入字典,對(duì)應(yīng)的條目是99。此時(shí)字典有一行數(shù)據(jù),如下圖所示。

第4行代碼將關(guān)鍵字'Excel星球'裝入字典,對(duì)應(yīng)的條目是98。此時(shí)字典就會(huì)有兩行數(shù)據(jù),如下圖所示。

……

但是我們前面講過(guò),字典的關(guān)鍵字必須是唯一的,如果字典中已經(jīng)存在了某個(gè)關(guān)鍵字,我們又往里面添加了同樣的關(guān)鍵字,會(huì)怎么樣呢?

舉個(gè)例子。






Sub 字典添加重復(fù)數(shù)據(jù)() Dim d As New Dictionary '聲明一個(gè)字典對(duì)象 d('看見(jiàn)星光') = 99 d('看見(jiàn)星光') = 59End Sub
第3行代碼將關(guān)鍵字'看見(jiàn)星光'裝入字典,對(duì)應(yīng)的條目是99。

第4行代碼再次裝入一個(gè)相同的關(guān)鍵字'看見(jiàn)星光',條目是59。此時(shí)字典會(huì)將已經(jīng)存在的關(guān)鍵字'看見(jiàn)星光'的條目更新為59。

如果我不想字典更新已經(jīng)存在的關(guān)鍵字記錄呢?憑什么把我從99分改為59分?對(duì)不對(duì)?我憑本事抄的答案你憑啥給我改成不及格?作為一個(gè)人,難道我連抄答案的自由都沒(méi)有了嗎?多么糟糕的組織會(huì)干出這樣無(wú)情的事?——摘自跨國(guó)出版物《星光日記》。

解決方案代碼如下▼








Sub 判斷字典是否存在相同關(guān)鍵字()    Dim d As New Dictionary '聲明一個(gè)字典對(duì)象    d('看見(jiàn)星光') = 99    If Not d.Exists('看見(jiàn)星光') Then        d('看見(jiàn)星光') = 59    End IfEnd Sub
第4行代碼使用字典的Exists方法判斷是否存在關(guān)鍵字'看見(jiàn)星光';如果不存在,則添加該關(guān)鍵字并設(shè)置條目為59;如果存在,則忽略不處理。

Exists是字典的方法,作用是判斷字典中是否存在指定關(guān)鍵字,結(jié)果返回一個(gè)布爾值,存在返回True,不存在返回False。語(yǔ)法格式如下▼

字典.Exists(關(guān)鍵字)
……

以上是講的如何將單個(gè)關(guān)鍵字裝入字典,那么如何將一組數(shù)據(jù)批量裝入字典呢?
如上圖所示的數(shù)據(jù)表,需要將A列的姓名作為關(guān)鍵字,B列的特長(zhǎng)作為條目,全部裝入字典——攤手,古老的VBA并沒(méi)有提供批量處理的方法,只能先將數(shù)據(jù)源存入數(shù)組,再遍歷數(shù)組將每個(gè)元素一一存入字典。

示例代碼如下▼








Sub 數(shù)據(jù)表數(shù)據(jù)存入字典()    Dim d As New Dictionary    Dim arr, i As Long    arr = Worksheets('數(shù)據(jù)表').Range('a1').CurrentRegion    For i = 2 To UBound(arr) '遍歷數(shù)組元素        d(arr(i, 1)) = arr(i, 2) '姓名是key,特長(zhǎng)是item    NextEnd Sub

第4行代碼將數(shù)據(jù)源數(shù)據(jù)存入數(shù)組arr

第5至第7行代碼遍歷數(shù)組元素,將姓名作為key,特長(zhǎng)作為item,分別存入字典。

……

一個(gè)小問(wèn)題,如何更新字典中指定關(guān)鍵字的條目呢?

假設(shè)字典中已經(jīng)存在關(guān)鍵字'看見(jiàn)星光',對(duì)應(yīng)的條目是99分;但是由于他這成績(jī)是抄別人答案抄來(lái)的,所以需要更改為59分。這時(shí)應(yīng)該怎么編寫代碼呢?——請(qǐng)返回本節(jié)中段,查看跨國(guó)出版物《星光日記》

……

4 丨

如何將數(shù)據(jù)從字典取出



了解了如何將數(shù)據(jù)裝入字典,接下來(lái)再看一下如何將數(shù)據(jù)從字典中取出,畢竟裝從來(lái)不是咱們的目的,咱們的目的是——要酷。字典的最大優(yōu)勢(shì)也并不在裝,而在于根據(jù)指定關(guān)鍵字取對(duì)應(yīng)條目的簡(jiǎn)潔和高效。

舉個(gè)例子。






Sub 讀取數(shù)據(jù)() Dim d As New Dictionary '聲明一個(gè)字典對(duì)象 d('看見(jiàn)星光') = 99 d('Excel星球') = 98 MsgBox d('Excel星球')End Sub
上述代碼中,第3行和第4行代碼將兩個(gè)關(guān)鍵字和對(duì)應(yīng)條目存入字典,第5行代碼獲取關(guān)鍵字'Excel星球'的對(duì)應(yīng)條目,并使用消息框顯示。

獲取字典指定關(guān)鍵字對(duì)應(yīng)Item的語(yǔ)法格式如下▼


字典(關(guān)鍵字)

就是這么簡(jiǎn)單~樸實(shí)無(wú)華且枯燥……

打個(gè)響指,我再舉個(gè)實(shí)用的例子。

如上圖所示的數(shù)據(jù)為例,需要根據(jù)A:B列的數(shù)據(jù)源,查詢D列人名對(duì)應(yīng)的特長(zhǎng),這就是所謂的條件查詢了。


示例代碼如下▼


















Sub 讀取數(shù)據(jù)2() Dim d As New Dictionary Dim arr, brr, i As Long arr = Range('a1').CurrentRegion '數(shù)據(jù)源 For i = 2 To UBound(arr) '遍歷數(shù)組,數(shù)據(jù)裝入字典 d(arr(i, 1)) = arr(i, 2) 'key是人名,item是特長(zhǎng) Next brr = Range('d1:e' & Cells(Rows.Count, 'd').End(xlUp).Row) '查詢區(qū)域 For i = 2 To UBound(brr) '遍歷查詢值 If d.Exists(brr(i, 1)) Then '如果字典存在查詢值            brr(i, 2) = d(brr(i, 1)) '獲取人名對(duì)應(yīng)的條目 Else            brr(i, 2) = '查無(wú)此人' End If Next Range('d1:e' & Cells(Rows.Count, 'd').End(xlUp).Row) = brr Set d = NothingEnd Sub

代碼解析:

第5至第7行代碼將數(shù)據(jù)源數(shù)據(jù)存入字典,其中人名為關(guān)鍵字,特長(zhǎng)為條目。

第8行代碼將查詢區(qū)域的數(shù)據(jù)存入數(shù)組brr。

第9行至第15行代碼遍歷獲取相關(guān)人名在字典中對(duì)應(yīng)的特長(zhǎng)。第10行代碼判斷字典中是否存在相關(guān)人名,如果存在,則取對(duì)應(yīng)的條目存入數(shù)組brr;如果不存在,則將結(jié)果設(shè)置為字符串'查無(wú)此人'。

第16行代碼將查詢結(jié)果寫入單元格區(qū)域。

代碼運(yùn)行后結(jié)果如下▼
……

字典除了支持通過(guò)指定關(guān)鍵字查詢對(duì)應(yīng)Item外,也支持一次性將所有的關(guān)鍵字或條目轉(zhuǎn)換為一維數(shù)組,這需要用到字典的Keys和Items屬性。

獲取字典所有的Key,語(yǔ)法格式如下▼


字典.Keys

獲取字典所有的Item,語(yǔ)法格式如下▼


字典.Items

……

我用麒麟雙臂給大家舉個(gè)典型的例子:數(shù)據(jù)去重。

如下圖所示的數(shù)據(jù)表,A列人名存在重復(fù)值,需要去重復(fù),獲取不重復(fù)的人員名單,結(jié)果如D列。


示例代碼如下▼














Sub 去重復(fù)()    Dim d As New Dictionary    Dim arr, i As Long    arr = Range('a1').CurrentRegion    For i = 1 To UBound(arr)        If Not d.Exists(arr(i, 1)) Then            d(arr(i, 1)) = ''        End If    Next    Range('d:d').ClearContents    Range('d1').Resize(d.Count, 1) = Application.Transpose(d.Keys)    Set d = NothingEnd Sub
代碼解析▼

第4行至第9行代碼將數(shù)據(jù)源的姓名作為關(guān)鍵字存入字典。很多新手朋友可能困惑于下面這句代碼。


d(arr(i, 1)) = ''


代碼的意思是姓名為關(guān)鍵字,條目為空文本。為什么要將條目設(shè)置為空文本?對(duì)于字典來(lái)說(shuō),Key和Item都是必須的,兩者必須成對(duì)出現(xiàn),缺一不可,但這里我們對(duì)Item并沒(méi)有特別的要求,所以就隨便賞個(gè)空文本打發(fā)一下算了。有朋友說(shuō),那我將代碼改成下面這樣行不行?——當(dāng)然可以!我真誠(chéng)的祝愿你夢(mèng)想成真!


d(arr(i, 1)) = '我想有個(gè)真人女朋友'

需要重點(diǎn)說(shuō)一下第11行代碼,它的作用是將字典所有關(guān)鍵字存入當(dāng)前工作表的D列。語(yǔ)句如下。


Range('d1').Resize(d.Count, 1) = Application.Transpose(d.Keys)

Count是字典的屬性之一,作用是統(tǒng)計(jì)字典關(guān)鍵字的數(shù)量,d.Count也就是名稱為d的字典有多少個(gè)關(guān)鍵字。

Range('d1').Resize(d.Count, 1),以d1單元格為起點(diǎn),向下擴(kuò)展指定行數(shù),作為存放字典所有關(guān)鍵字的單元格區(qū)域。

d.Keys是以一維數(shù)組的形式返回字典所有的關(guān)鍵字。在數(shù)組四篇里咱們講過(guò),一維數(shù)組就是一行數(shù)據(jù),需要通過(guò)Transpose函數(shù)進(jìn)行一次轉(zhuǎn)置才能轉(zhuǎn)換為二維,然后才能直接寫入垂直單元格區(qū)域。

綜上所述——這四個(gè)字老霸氣了,但更霸氣的是隨后的四個(gè)字——您就懂了!

……

擴(kuò)展一下,我再舉個(gè)與之相似的例子。

如下圖所示,需要在D:E列,獲取A:B列不重復(fù)的人名及其特長(zhǎng)數(shù)據(jù)。


示例代碼如下▼














Sub 去重復(fù)2()    Dim d As New Dictionary    Dim arr, i As Long    arr = Range('a1').CurrentRegion    For i = 1 To UBound(arr)        If Not d.Exists(arr(i, 1)) Then            d(arr(i, 1)) = arr(i, 2)        End If    Next    Range('d:e').ClearContents    Range('d1').Resize(d.Count, 2) = Application.Transpose(Array(d.Keys, d.Items))    Set d = NothingEnd Sub

和上一段代碼相比,所不同的有兩句。

第7行代碼,d(arr(i, 1)) = arr(i, 2),指定了關(guān)鍵字對(duì)應(yīng)的條目為arr(i,2),也就是人員的特長(zhǎng)。為什么不再是d(arr(i, 1)) = ''了?因?yàn)槟阈枰狪tem為指定值,不能再隨便打發(fā)了。人吶,就是這么現(xiàn)實(shí)。

第11行代碼放置數(shù)據(jù)的列數(shù)由1列改為了2列。

Range('d1').Resize(d.Count, 2)

代碼使用以下語(yǔ)句一次性獲取字典的Keys和Items,存入一個(gè)一維數(shù)組(在數(shù)組四篇里咱們講過(guò),Array函數(shù)結(jié)果為一維數(shù)組),最后再通過(guò)一次轉(zhuǎn)置將一維數(shù)組修改為2維,直接寫入指定單元格區(qū)域。


Application.Transpose(Array(d.Keys, d.Items))

……

5 丨

如何移除字典中的元素



前面講了如何對(duì)字典的數(shù)據(jù)進(jìn)行存和取,這是使用字典最常見(jiàn)的兩種情況;但還有一種情況:移除,也就是將數(shù)據(jù)從字典中移除。

如果移除指定關(guān)鍵字,可以使用方法Remove,語(yǔ)法格式如下▼


字典.Remove 關(guān)鍵字

示例代碼如下:







Sub 移除指定關(guān)鍵字()    Dim d As New Dictionary '聲明一個(gè)字典對(duì)象    d('看見(jiàn)星光') = 99    d('Excel星球') = 98    d.Remove '看見(jiàn)星光'End Sub

第3行和第4行代碼分別添加兩個(gè)關(guān)鍵字到字典中。此時(shí)字典有兩行數(shù)據(jù),如下圖所示▼

第5行代碼將關(guān)鍵字'看見(jiàn)星光'移除,關(guān)鍵字和條目總是成對(duì)出現(xiàn)的,關(guān)鍵字移除了,對(duì)應(yīng)的條目也就移除了,于是此時(shí)字典就還剩下一個(gè)關(guān)鍵字▼


除了根據(jù)指定關(guān)鍵字移除數(shù)據(jù)外,還可以使用方法RemoveAll將字典數(shù)據(jù)一次性清空。語(yǔ)法格式如下▼


字典.RemoveAll


當(dāng)一個(gè)字典需要重復(fù)使用的時(shí)候,就需要用上RemoveAll方法了。

舉個(gè)例子,如下圖所示,需要在H列獲取每期開(kāi)獎(jiǎng)號(hào)碼不重復(fù)的號(hào)碼,并用逗號(hào)作為分隔符,合并成一個(gè)字符串。


示例代碼如下▼

















Sub 全部移除字典中的元素()    Dim d As New Dictionary    Dim arr, i As Long, j As Long    arr = Range('a1').CurrentRegion    For i = 2 To UBound(arr) '遍歷行        d.RemoveAll '移除字典中所有的元素        For j = 2 To UBound(arr, 2) - 1 '遍歷列            If Not d.Exists(arr(i, j)) Then                d(arr(i, j)) = '' '將不重復(fù)的號(hào)碼存入字典            End If        Next        arr(i, UBound(arr, 2)) = VBA.Join(d.Keys, ',') '合并為一個(gè)字符串    Next    Range('a1').CurrentRegion = arr    Set d = NothingEnd Sub
第5行代碼遍歷處理每行數(shù)據(jù)。

第6行代碼在實(shí)際處理每行數(shù)據(jù)之前,先清空字典中的所有元素。

第7至第11行代碼遍歷當(dāng)前行每列的元素,只將唯一值存入字典。

第12行代碼使用Join函數(shù),以逗號(hào)為分隔符,將當(dāng)前字典所有的關(guān)鍵字合并成為一個(gè)字符串,并存入結(jié)果數(shù)組。


arr(i, UBound(arr, 2)) = VBA.Join(d.Keys, ',')

然后再遍歷處理下一行數(shù)據(jù)……

……


6 丨

如何遍歷字典中的元素



有時(shí)候,為了篩選出符合條件的數(shù)據(jù),我們需要像遍歷數(shù)組一樣,遍歷字典中的每個(gè)元素。這通常需要先獲取字典的Keys集合,再遍歷每個(gè)Key去篩選字典中符合條件的數(shù)據(jù)。

什么意思呢?舉個(gè)例子還是我。

如下圖所示的數(shù)據(jù)表,需要篩選出人名重復(fù)出現(xiàn)次數(shù)大于2次的人員名單,以及相關(guān)出現(xiàn)次數(shù),結(jié)果參考C:D列。

示例代碼如下▼





















Sub 遍歷字典元素_索引法()    Dim d As New Dictionary    Dim arr, aKey, aRes, i As Long, k As Long    arr = Range('a1').CurrentRegion    For i = 2 To UBound(arr)        d(arr(i, 1)) = d(arr(i, 1)) + 1    Next    aKey = d.Keys    ReDim aRes(1 To d.Count, 1 To 2) '結(jié)果數(shù)組    For i = 0 To UBound(aKey)        If d(aKey(i)) > 2 Then '次數(shù)大于2次            k = k + 1            aRes(k, 1) = aKey(i)            aRes(k, 2) = d(aKey(i))        End If    Next    Range('c:c').ClearContents    Range('c1') = '重復(fù)2次以上的人名'    Range('c2').Resize(k, 2) = aRes    Set d = NothingEnd Sub

代碼解析:

第4行代碼將數(shù)據(jù)源數(shù)據(jù)存入數(shù)組arr。

第5行至第7行代碼將數(shù)組arr中的人名存入字典,重點(diǎn)是下面這句代碼。


d(arr(i, 1)) = d(arr(i, 1)) + 1

這句代碼類似于咱們?cè)谑裁词亲兞坷镏v過(guò)的計(jì)數(shù)器k=k+1。

作為賦值語(yǔ)句,它首先運(yùn)算的是等號(hào)右側(cè)的表達(dá)式:d(arr(i,1))+1。有趣的是,在代碼運(yùn)行這里的d(arr(i,1))的時(shí)候,我們還沒(méi)有將arr(i,1)的關(guān)鍵字存入字典,所以正常理解,這句代碼應(yīng)該返回程序錯(cuò)誤,但事實(shí)并沒(méi)有。字典(關(guān)鍵字)語(yǔ)句的運(yùn)算規(guī)則是,如果字典中存在指定關(guān)鍵字,則返回對(duì)應(yīng)的Item,否則會(huì)將該關(guān)鍵字存入字典,同時(shí)將其對(duì)應(yīng)的Item設(shè)置為Nothing。
因此,在第一次運(yùn)行這句代碼時(shí)……


d(arr(i, 1)) = d(arr(i, 1)) + 1

等于▼


d(arr(i, 1)) = Nothing + 1

等于▼


d(arr(i, 1)) =1

也就是在字典中存入一個(gè)關(guān)鍵字arr(i,1),對(duì)應(yīng)的條目為1。

當(dāng)出現(xiàn)第2次出現(xiàn)同名的關(guān)鍵字時(shí)…


d(arr(i, 1)) = d(arr(i, 1)) + 1

等于▼


d(arr(i, 1)) = 1 + 1

等于▼


d(arr(i, 1)) = 2

也就是在字典將關(guān)鍵字arr(i,1)對(duì)應(yīng)的條目更新為2.

……以此實(shí)現(xiàn)了相同值出現(xiàn)次數(shù)在字典中不斷累加的效果。

你品品,是不是這個(gè)道理?品不出來(lái)?沒(méi)事,不怕你墮落,我送你一瓶82年的雪碧,你慢慢品。



……

第8行代碼返回字典中所有的Key,結(jié)果是一個(gè)下標(biāo)為0的一維數(shù)組,命名為aKey。

第9行代碼聲明一個(gè)結(jié)果數(shù)組,行數(shù)為字典的個(gè)數(shù),列數(shù)是2列,一列放人名,一列放次數(shù)。

第10行至第16行代碼采用索引的方式遍歷數(shù)組aKey,查看每一個(gè)Key在字典中的Item是否大于2次,如果大于2次則將Key和Item分別存入結(jié)果數(shù)組。相似的套路咱們?cè)跀?shù)組4篇的數(shù)組運(yùn)算里詳細(xì)講過(guò)了,這里就不再敲擊鍵盤,免得浪費(fèi)它所剩無(wú)幾的生命力。

……

7 丨

如何釋放字典內(nèi)存



如果你是細(xì)心的人兒,會(huì)發(fā)現(xiàn)前面每小節(jié)的代碼末尾都會(huì)出現(xiàn)下面這條語(yǔ)句。

Set d = Nothing

在章節(jié)什么是變量里咱們講過(guò)了,它的作用是釋放對(duì)象變量所占用的內(nèi)存,提高代碼運(yùn)行效率,雖然它未必是必須的,但聰明的您最好像優(yōu)秀的我一樣,養(yǎng)成使用它的好習(xí)慣。

有朋友可能會(huì)問(wèn),我用字典.RemoveAll語(yǔ)句清空字典,是不是可以代替Set 字典=Nothing?答案是否定的,你失戀了,傷感的把合租的房子清空,和你一怒之下把房子給燒沒(méi)了,是兩個(gè)概念好吧?前者房子雖然空了,但還在,還能住新歡和舊愛(ài),后者是連房子都沒(méi)了,再愛(ài)也都煙消云散了……。


8 丨

思考題和其它



最后說(shuō)一下幾個(gè)零散的知識(shí)點(diǎn)。

……

1丨前期綁定和后期綁定的不同

在本章第2節(jié)如何創(chuàng)建字典,咱們講過(guò),有些屬性前期綁定是支持的,但后期綁定并不能使用。這個(gè)有些屬性,其實(shí)指的就是Items和Keys。

在前期綁定的情況下,我們可以使用以下語(yǔ)句讀取Keys集合的指定索引元素。

讀取字典Keys的第2個(gè)元素,并賦值為變量strKey..▼

strKey = d.Keys(1)

但后期綁定并不支持運(yùn)行該語(yǔ)句,必須先將Key或Item轉(zhuǎn)換為數(shù)組才能夠索引遍歷。

讀取字典Keys的第2個(gè)元素,并賦值為變量strKey..▼


r = d.Keys'關(guān)鍵字集合賦值數(shù)組rstrKey = r(1)

……

2丨如何讓字典不區(qū)分字母大小寫

字典是默認(rèn)是區(qū)分字母大小寫的。如果不需要區(qū)分字母大小寫,有兩種解決方法……

一種是設(shè)置字典的CompareMode屬性為TextCompar,示例代碼如下▼







Sub 不區(qū)分字母大小寫() Dim d As New Dictionary d.CompareMode = TextCompare d('a') = 1 MsgBox d('A')End Sub

一種是將所有的字母統(tǒng)一轉(zhuǎn)換為大寫(UCase)或小寫(LCase),這種方式明顯修改了原值,因此通常不建議使用。示例代碼如下▼






Sub 不區(qū)分字母大小寫2()    Dim d As New Dictionary    d(LCase('a')) = 1'LCase將字母統(tǒng)一轉(zhuǎn)換為小寫    MsgBox d(LCase('A')) End Sub

……

3丨字典對(duì)數(shù)據(jù)類型的態(tài)度是嚴(yán)格的

字典對(duì)數(shù)據(jù)類型的態(tài)度是嚴(yán)格的——這句話是什么意思呢?我們知道Excel是一款對(duì)數(shù)據(jù)類型要求很寬松的軟件,數(shù)值可以分為文本型數(shù)值和純數(shù)值兩種,在VBA的邏輯判斷中,文本型數(shù)值和純數(shù)值是相等的,比如以下代碼返回True。




Sub t() MsgBox '1' = 1End Sub

但在字典中,純數(shù)值和文本型數(shù)值并不相等。

舉個(gè)例子,示例代碼如下▼






Sub 數(shù)據(jù)類型1()    Dim d As New Dictionary    d(1) = '愛(ài)就一個(gè)字'    MsgBox d.Exists('1')End Sub

第3行代碼將純數(shù)值1作為Key存入字典。

第4行代碼判斷文本型數(shù)值1在字典中是否存在,結(jié)果返回False。

知道這個(gè)知識(shí)點(diǎn)有什么用?

當(dāng)你需要處理的Key有數(shù)值類型時(shí),最好將源數(shù)據(jù)和查詢值都統(tǒng)一轉(zhuǎn)換為文本的形式,避免踩坑。如何統(tǒng)一轉(zhuǎn)換為文本的形式?可以通過(guò)聲明一個(gè)字符串類型的變量,強(qiáng)制進(jìn)行轉(zhuǎn)換。

示例代碼如下▼











Sub 數(shù)據(jù)類型2() Dim d As New Dictionary Dim strKey As String '定義一個(gè)字符串類型的變量 strKey = '1' d(strKey) = '愛(ài)就一個(gè)字' strKey = '2' d(strKey) = '我要說(shuō)兩次' strKey = 1 '強(qiáng)制轉(zhuǎn)換為字符串 MsgBox d.Exists(strKey) '結(jié)果返回TrueEnd Sub

……

4丨字典常用方法和屬性的另外表達(dá)方式

如果你看的VBA代碼多了,可能會(huì)看到有人使用以下方式往字典中添加關(guān)鍵字和對(duì)應(yīng)條目:


d.Add '夏天','吃冰棍'

其中夏天是Key,吃冰棍是Item。

但這種方式在常規(guī)VBA代碼中我并不推薦使用,原因很簡(jiǎn)單,它不夠靈活。如果字典中已存在相同關(guān)鍵字,該語(yǔ)句會(huì)返回錯(cuò)誤值,而且它并不支持更新相關(guān)條目。當(dāng)然,最重要的是,它打字太多了,你數(shù)數(shù),相比下句代碼它多打了幾個(gè)字?別不把手指當(dāng)親骨肉啊同志們吶!!


d('夏天')='吃冰棍'

與之相似的還有下面幾種語(yǔ)句,同樣因?yàn)椴粔蜢`活,打字偏多等不推薦使用。







Sub test1()    Dim d As New Dictionary    d.Add '看見(jiàn)星光', '曾經(jīng)20歲' '添加一個(gè)關(guān)鍵字看見(jiàn)星光    MsgBox d.Item('看見(jiàn)星光') '獲取關(guān)鍵字看見(jiàn)星光對(duì)應(yīng)的條目    d.Item('看見(jiàn)星光') = '年年18歲' '將看見(jiàn)星光對(duì)應(yīng)的條目修改為'年年18歲'End Sub

5丨如何學(xué)習(xí)更多VBA編程知識(shí)和技巧?

字典是VBA編程中的核心數(shù)據(jù)結(jié)構(gòu),本文只是講解了最基礎(chǔ)的概念和用法,字典存在的意義到底是什么??jī)H僅只是去重復(fù)嗎?簡(jiǎn)單的數(shù)據(jù)查詢嗎?當(dāng)然不是!更多實(shí)用的字典用法我會(huì)繼續(xù)分享在知識(shí)星球……

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多