目录
3.1引入“Microsoft Scripting Runtime库”前期绑定
0.《VBA实用编程技巧》专栏总纲
本文作为专栏《VBA实用编程技巧》专栏其中的一部分,返回专栏总纲,阅读所有文章,点击Link:
在很多编程语言中都有“字典”这个功能,比如Python,Java,C#等,“字典”功能是非常好用的,我在平常的编程中也经常使用。最近这些年Python比较火,很多人都知道Python的字典功能,那么VBA可不可以用呢。答案是可以的。现在我分享一下我个人对VBA字典功能的一些理解。
1.什么是“字典”
字典(Dictionary)是一种数据结构,用于存储“键值对”。它是一个无序的集合,其中每个元素都由一个键和一个值组成。字典中的键必须是唯一的,VBA字典的值不和其他语言一样可以是任意值,需要是VBA里定义的基本类型,但是我们也是有办法来处理的,可参阅我前面的博客文章(VBA如何把用户自定义Type类型数据存入字典-CSDN博客)。 字典可以通过键来访问和修改对应的值,而不需要遍历整个集合。这使得字典非常适合用于存储和检索大量数据,特别是当需要根据某个唯一标识符来查找对应的值时。
字典的键必须是唯一的,但值却不要求唯一,这和我们平常用的新华字典是一个道理,字典里一个字一个含义,但具有相同含义的可能有多个字。如下表所示,我们定义一个班级学生成绩等级的字典,那么姓名就是唯一的,但成绩等级可能很多同学都是一样的。
表1.字典键值对实例
键 | Jim | Lily | Tom | Jorn | Lucy | Brown | Jack |
值 | Grade-A | Grade-B | Grade-B | Grade-C | Grade-D | Grade-B | Grade-A |
2.字典的优势
字典的优势总结如下:
[1]灵活性:字典非常适合存储复杂的数据结构。
[2]高效性:字典查找操作通常非常快。这对于需要频繁查找和检索数据的应用程序来说是非常有益的。
[3]易读性:使用字典可以使代码更加清晰和易读。通过有意义的键来访问数据,可以使代码更易于理解和维护。
[4]减少代码量:使用字典可以避免编写冗长的条件语句或循环来查找和检索数据,从而简化代码并减少出错的可能性
3.VBA中字典的创建方法
VBA中字典常见有2中使用方法:
3.1引入“Microsoft Scripting Runtime库”前期绑定
引入Microsoft Scripting Runtime库的方法是在VBA编辑器中选择“工具”菜单下的“引用”,然后勾选“Microsoft Scripting Runtime”库。之后就可以在代码中直接声明和使用Dictionary对象了。如图1.
图1. 引入Microsoft Scripting Runtime库
字典的创建方法如下代码所示:
Sub DicTest()
Dim dict As Scripting.Dictionary '字典类型
Set dict = New Scripting.Dictionary 'New关键字新建字典对象
End Sub
这种前期绑定的方法创建的字典,优势是写代码时会有代码提示,可以调用字典对象的属性和方法列表,提高开发速度,也避免了拼写上的错误,如图2。但前期绑定这种方法可能使得代码在其他电脑上无法运行,比如其他人没有点开这个引用,代码就无法执行了。也就是这种方法方便了开发者但不利于使用者。
图2.属性和方法自动提示
3.2通过CreateObject函数后期绑定
后期绑定这种方法,就不用引用Microsoft Scripting Runtime这个库,代码可以直接给其他用户直接使用,但缺点是写代码的时候不会弹出属性和方法列表,用户必须得自己记得字典的属性和方法名称,容易出现拼写错误。也就是这种方法不利于开发者但利于使用者。为了代码的适应性,平常我都是用后一个方法。
这个方式字典创建方法如下:
Sub DicTest()
Dim dict As Object '定义一个object变量
Set dict = CreateObject("Scripting.Dictionary") 'Set关键字创建一个Scripting.Dictionary的实例
End Sub
4.VBA字典的属性和方法
两种方式创建的字典,属性和方法是一样的,后一种方法没有代码提示,需要自己记住。VBA的字典有Add,Items,Keys,Remove,RemoveAll和Exists六个方法,有Item,Key,Count和CompareMode四个属性。如图3.下面分别介绍:
图3.VBA字典的方法和属性
4.1 Add方法
[功能]:给字典添加一条新的“键值对”
[语法]:dict.Add key,item
其中key,代表键,item是该键对应的值。key建议采用文本String的形式。实例代码如下:
Sub DicTest()
Dim dict As Scripting.Dictionary '字典类型
Set dict = New Scripting.Dictionary 'New关键字新建字典对象
dict.Add "Jorn", "Grade-A" '添加对象,Jorn,等级为Grade-A
Debug.Print dict.Item("Jorn") '打印测试
'输出结果:Grade-A
End Sub
由于字典要求键必须是唯一的,如果往字典中添加已经存在的值,程序就会报错,因此我们往字典内添加值都是配合后面Exists方法一起使用,即先判断字典中是否存在该键值,只有在不存在的时候才用Add方法添加新的键值对。代码如下:
If Not dict.Exists("Jorn") Then
dict.Add "Jorn", "Grade-A" '添加对象,Jorn,等级为Grade-A
End If
4.2 Key属性
[功能]:修改字典的键值
[语法]:dict.Key(key)=newkey
Key属性主要是修改字典已存“键”的值,比如上面代码创建的代码,把学生“Jorn”改为"Jim”.
Sub DicTest()
Dim dict As Scripting.Dictionary '字典类型
Set dict = New Scripting.Dictionary 'New关键字新建字典对象
If Not dict.Exists("Jorn") Then
dict.Add "Jorn", "Grade-A" '添加对象,Jorn,等级为Grade-A
End If
dict.Key("Jorn") = "Jim" '修改Jorn为Jim
'判断一下Jorn是否还存在
If dict.Exists("Jorn") Then
Debug.Print "Jorn还存在。"
Debug.Print "Jorn的成绩:" & dict.Item("Jorn") '打印测试
Else
Debug.Print "Jorn没有了!"
Debug.Print "Jim的成绩:" & dict.Item("Jim") '打印测试
End If
'输出结果如下:
'**************************************************************
'Jorn没有了!
'Jim的成绩: Grade -A
'**************************************************************
End Sub
需要特别注意,字典的Key属性是可写不可读的,例如下面语句就是错误的,dict.Key("Jorn")是没有对应值的。
'下面代码是错误的,字典的Key属性可写不可读
Dim val As String
val = dict.Key("Jorn")
4.3 Item属性
[功能]:返回字典键对应的值,或者修改键对应的值,可写也可以读,
[语法]:■作为返回值读取的时候:dict.Item(key)
■修改键对应值的时候:dict.Item(key)=newItem
Items属性也可以不加".Item",而直接使用dict(key)的方式也是可以的,如下代码所示。
Sub DicTest()
Dim dict As Scripting.Dictionary '字典类型
Set dict = New Scripting.Dictionary 'New关键字新建字典对象
If Not dict.Exists("Jorn") Then
dict.Add "Jorn", "Grade-A" '添加对象,Jorn,等级为Grade-A
End If
'1-Item属性读取Jorn的成绩
Debug.Print dict.Item("Jorn")
'**************运行结果****************
'Grade-A
'****************************************
'2-Item属性修改Jorn的成绩
dict.Item("Jorn") = "Grade-D"
Debug.Print dict.Item("Jorn")
'**************运行结果****************
'Grade-D
'****************************************
'3-Item的等效表达形式
dict("Jorn") = "Grade-B"
Debug.Print dict("Jorn")
'**************运行结果****************
'Grade-B
'****************************************
End Sub
4.4 Exists方法
[功能]:判断字典中是否存在某个键,存在返回True,否则返回False
[语法]:dict.Exists(key)
代码就不举例了,参考前面代码示例。
4.5 Count属性
[功能]:返回字典中的条目数量
[语法]:dict.Count
Sub DicTest()
Dim dict As Scripting.Dictionary '字典类型
Set dict = New Scripting.Dictionary 'New关键字新建字典对象
If Not dict.Exists("Jorn") Then
dict.Add "Jorn", "Grade-A" '添加对象,Jorn,等级为Grade-A
End If
If Not dict.Exists("Jim") Then
dict.Add "Jim", "Grade-C" '添加对象,Jim,等级为Grade-C
End If
Debug.Print dict.Count
'**************运行结果****************
'2
'****************************************
End Sub
4.6 Keys方法与Items方法
[功能]:Keys方法返回字典所有键的一维数组,Items方法返回字典所有值的一维数组
[语法]:dict.Keys,dict.Items
如下代码所示,我们可以遍历字典的所有键和值,并输出。dict.Keys,dict.Items其实都是数组,所以我们也可以和使用数组一样用序号来引用:dict.Keys(0)就代表字典的第一个值,dict.Items也同理。需要注意,dict.Items,dict.Keys的数组序号是从0开始的。
Sub DicTest()
Dim dict As Scripting.Dictionary '字典类型
Set dict = New Scripting.Dictionary 'New关键字新建字典对象
If Not dict.Exists("Jorn") Then
dict.Add "Jorn", "Grade-A" '添加对象,Jorn,等级为Grade-A
End If
If Not dict.Exists("Jim") Then
dict.Add "Jim", "Grade-C" '添加对象,Jorn,等级为Grade-A
End If
' 遍历字典的键
Dim key As Variant
For Each key In dict.Keys
Debug.Print "Key: " & key
Next key
' 遍历字典的值
Dim value As Variant
For Each value In dict.Items
Debug.Print "Value: " & value
Next value
' 用序号索引遍历键和值
Dim i As Integer
For i = 1 To dict.Count
Debug.Print "Key: " & dict.Keys(i - 1) & ", Value: " & dict.Items(i - 1)
Next i
End Sub
4.7 Remove和RemoveAll方法
[功能]:Remove删除字典一个键值对,RemoveAll删除字典所有键值对
[语法]:dict.Remove(key),dict.RemoveAll
dict.Remove ("Jim")
dict.RemoveAll
4.8 CompareMode属性
[功能]:设置或者返回字典比较字符串的模式,即是否区分大小写。默认值为0,区分大小写。
[语法]:dict.CompareMode[=mode]
mode的值有3种:
vbBinaryCompare:区别大小写
vbTextCompare:不区分大小写
vbDatabaseCompare使用数据库比较规则。在这种模式下,键的比较是基于数据库中的排序规则进行的。(惭愧^-^,目前我从没用过...)
需要注意:CompareMode属性只能在新建字典的时候设置,如果字典已经建好赋值了,再修改这个属性为其他模式是不允许的,程序会报错。
代码示例:
Sub DicTest()
Dim dict As Scripting.Dictionary '字典类型
Set dict = New Scripting.Dictionary 'New关键字新建字典对象
If Not dict.Exists("Jorn") Then
dict.Add "Jorn", "Grade-A" '添加对象,Jorn,等级为Grade-A
End If
Debug.Print dict.CompareMode
If dict.Exists("JORN") Then
Debug.Print "存在大写的JORN"
Else
Debug.Print "不存在大写的JORN"
End If
'*************运行结果*************
'0
'不存在大写的JORN
'************************************
'下面修改一下字典的CompareMode属性,改为不区别大小写
'[注意CompareMode属性只能在新建字典的时候设置,如果字典已经建好赋值了,再改为其他属性是不允许的]
'下面重新赋值一个字典测试
Dim dictNew As Scripting.Dictionary '字典类型
Set dictNew = New Scripting.Dictionary 'New关键字新建字典对象
dictNew.CompareMode = TextCompare '需要新建的时候就提前指定,不能后面再设置
If Not dictNew.Exists("Jorn") Then
dictNew.Add "Jorn", "Grade-A" '添加对象,Jorn,等级为Grade-A
End If
Debug.Print dictNew.CompareMode
If dictNew.Exists("JORN") Then
Debug.Print "存在大写的JORN"
Else
Debug.Print "不存在大写的JORN"
End If
'*************运行结果*************
'1
'存在大写的JORN
'************************************
dictNew.CompareMode = TextCompare
End Sub