字典作为一种复合数据类型和封装有属性和方法的对象,自然比自己定义来得更加方便、安全和有效率。
字典其实就是一些“键-值”对。在很多场合,它都能起到很大的作用,使用起来非常方便,有类似于微型数据库的作用,可用于临时保存一些数据信息。
字典相当于一个多行二列的二维数组或单元格数据区域。
字典这种数据结构有两个很重要的特性:
I key(键)不允许重复。当给字典元素赋值时,不存key时可以新建,存在key时可以更新值。利用这个特性可以很方便地做一些数据汇总的工作。这个机制就会形成键值覆盖。这是字典区别于VBA的另一种数据类型,集合(Collection)的一个重要方面。如果你曾经试图改变某个与Collection对象成员对应的键值,那么你知道这不可能。当对象成员加入到Collection对象时,该成员的数据和键值就已经被固定下来了。你能做的唯一选择就是使用Remove方法清除该成员并增加一个新成员到该对象。但是,你能够利用字典(Dictionary)对象的Key特性来覆盖该键的键值。
II 数据元素通过key进行索引,我们知道,数据是通过下标进行索引的,所以顺序很重要。而字典是通过key进行索引的,所以不考虑元素顺序。通过key进行索引,在特定的场合,有它的优势所在。
1 声明字典
VBA中创建字典有两种方法:
1.1 引用声明
在VBE菜单中,选择“工具-引用”,在弹出的对话框中选择中边的“浏览”,此时会打开Windows系统的驱动目录(C:\Windows\System32),然后找到,确定确定返回就行了。
添加引用后,就可以像定义其它变量一样声明使用字典了。
Sub test()
Shell ("Regsvr32 C:\Windows\System32\Scrrun.dll") 'Dos 下运行注册DLL
'Toos -> References -> Microsoft Scripting Runtime 'VBE中工具、引用
Dim dic As New Dictionary '前期绑定后就可以直接定义字典类型变量并初始化
For i = 1 To 10
dic(i) = i * 10
Next
t1 = dic.keys(2) '然后就可以直接读取第3个字典元素的关键词(注意字典数组是0开始)
t2 = dic.Items(2) '同样可以直接读取第3个字典元素的项目内容(注意字典数组是0开始)
End Sub
1.2 直接声明
Dim d As Object
Set d = CreateObject("Scri;)
2 字典的方法
既然是一种对象类型,它肯定封装了若干成员方法和属性。
字典有6个成员方法,分别是Add、Exists、Keys、Items、Remove、RemoveAll。使用方法如下:
2.1 Add
用于添加内容到字典中。
d.Add key, item
第一个参数为键,第二个参数为键对应的值。
如d.Add "优秀", 80
一般使用直接赋值的方式来把内容添加到字典中:
d.(key) = item,如:
dic("及格") = 60
'Add [key/item] if key is new
'如果key不存在则直接加入[key/item]
dic("及格") = 70
'Cover [item] if key is exists without Err
'如果key存在则覆盖更新item 且不产生key存在的错误提示
'因此本质上,用这个方法给字典赋值、比使用 Dic.Add, item 更好!
'如需要对key存在进行错误处理,可使用Dic.Exists(key)方法,更加灵活。
2.2 Exists()
用于判断指定的关键词是否存在于字典(的键)中。
d.Exists(key)
如果存在,返回True,否则返回False。通常会在向字典中添加条目的时候使用,即先判断字典中是否已存在这个记录,如果不存在则新增,否则进行其它的操作。
2.3 Keys()
获取字典所有的键,返回类型是数组。
d.Keys()
值得注意的是,字典使用for each next结构进行遍历时,返回的是key。
For Each di In d
k = k + 1
Cells(k, 15) = dic(di)
Next
2.4 Items()
获取字典所有的值,返回类型是数组。
d.Items()
2.5 Remove()
从字典中移除一个条目,是通过键来指定的。
d.Remove(key)
如果指定的键不存在,会发生错误。
2.6 RemoveAll
清空字典。
d.RemoveAll
3 字典的属性
字典有4个属性:Count、Key、Item、ConpareMode
3.1 Count
用于统计字典中键-值对的数量。也可以简单理解为统计字典中键的个数。
常用在字典遍历时配合循环使用,如:
For i = 0 To d.Count - 1
3.2 Key
用于更改字典中已有的键。如:
d.Key("apple") = "Orange"
如果指定的键不存在,则会产生错误。
3.3 Item
用于写入或读取字典中指定键的值,如果指定的键不存在,则会新增。如:
'读取
Debug.Print d.Item("apple")
'写入
d.Item("apple") = 10
3.4 CompareMode
当用字符串做为key时是否区分大小写,如 Dic.CompareMode=1不区分大小写,Dic.CompareMode=0区分大小写
默认不写是区分的。
Sub test10()
Dim dic
Set dic = CreateObject("Scri;)
dic.Add "D", 0
dic.Add "d", 0
'因为默认的是区域大小写的,所以不报错
End Sub
Sub test11() '不区分大小写,
Dim dic
Set dic = CreateObject("Scri;) '后期绑定引用字典对象
dic.CompareMode = 1
dic.Add "D", 0
dic.Add "d", 0
'上面的代码报错了,因为dic.CompareMode = 1不区分大小写,所以
'你装后大写的D之后,再装小写的d,重装了,报错
End Sub
4 总结一下:字典元素的添加、访问
任何语言的复合数据类型,做为一种数据元素容器,都要考虑数据元素的增、查、删、改,并用适当的成员方法封装起来。
4.1 字典元素的添加
d.Add "a", "example1"
d.Add "b", 9
'd.Add "b", 7 'add重复key会报错
d("b") = 7 '这样会直接覆盖,不会报错
'd.Item("b") = 7 '与上者相同
d("c") = "example2"
4.2 字典元素值通过key的访问
Cells(1, 1) = d("a")
'Cells(1, 1) = d.Item("a") '与上者相同
5 字典映射到单元格区域
'把字典中keys/items结果分别输出到工作表的某一列
[a1].Resize) = Work) 'Output keys result
[b1].Resize) = Work) 'Output items result
6 实例应用:将单元格区域映射到数组,字典通过数组定义来汇总数据。
如下图所示,按姓名汇总数据:
下面左边数据是源数据,中间是使用VBA统计产生的数据,右边是使用数据透视表产生的数据。
Sub 数据汇总()
Dim dict, mrow, arr
Set dict = CreateObject("Scri;)
mrow = Range("a" & Rows.Count).End(xlUp).Row
arr = Range("A2:C" & mrow)
For i = 1 To UBound(arr)
dict(arr(i, 1)) = dict(arr(i, 1)) + arr(i, 3)
Next i
[f1] = [a1]
[g1] = [c1]
[F2].Resize, 1) = Application.Work)
[G2].Resize, 1) = Application.Work)
End Sub
代码运行后,实现与数据透视表汇总数据相同的效果。
当然上面也可以不使用数组,直接引用单元格,但使用数据操作起来更方便,不需要考虑单元格偏移。
7 实例应用:数组与字典配合使用统计数据
如下,统计得票数:
Sub 投票统计()
Dim dict, mrow, arr
Set dict = CreateObject("Scri;)
mrow = Range("b" & Rows.Count).End(xlUp).Row
arr = Range("B2:D" & mrow)
For i = 1 To UBound(arr)
For j = 1 To UBound(arr, 2)
dict(arr(i, j)) = dict(arr(i, j)) + 1
Next j
Next i
[G1] = "候选人"
[H1] = "得票汇总"
[G2].Resize, 1) = Application.Work)
[H2].Resize, 1) = Application.Work)
End Sub
由于字典的“键、值”存储模式只能对应多行两列的数据结构,一列是键,一列是值。如果值汇总时需要考虑两列的关键字,如某个表格的编排有三列数据,产品名称、规格、数量,如果需要按产品名称+规格去汇总数量。则需要考虑将产品名称与规格通过字符串连接的方式连接起来做为字典的键。
-End-