当你发现不停的用For循环来处理数据速度慢的受不了了,你肯定会想怎么才能提高一些效率。比如前面我们说到的对比2个表数据,我们是使用For循环去逐个的对比判断,如果能有1个东西让我们可以快速的在一组数据里找到需要的、或者是找不到的时候返回false的话,那我们就不需要用For循环了,那有没有这种东西呢?
是的,今天要说到的字典就是这么一个东西,作为1个新手,可能你只需要知道它有快速找到某个数据的功能就可以了。如果你还有兴趣深入了解,那就需要去学习数据结构和算法方面的东西了,字典就是一种Hash算法实现的东西。
1、COM对象
字典就是Windows系统做好了的一个东西,是一种叫做COM对象的东西,在VBA中如果要使用的话,有2种方法:
- 前期绑定:
在VBA编辑器里点击工具-引用,找到需要使用的项目勾选
- 后期绑定:
使用VBA的CreateObject函数,这种情况下要知道COM对象的名称。
代码语言:javascript复制VBA.CreateObject("XXXXX")
这样就可以在VBA里使用该对象了,2种方法有一点小的差异,主要是:
- 前期绑定的方法使用对象时就像是使用VBA内部对象一样了,但是一旦你把做好的程序发给别人使用,使用者也必须要手动先添加引用。
- 后期绑定不需要手动添加引用,但是使用过程中不大方便,不能直接声明对象的名称,要用Object代替,写代码也不会像VBA内部对象那样自动列出属性和方法。
作为VBA的使用者,知道这样使用COM就可以了。
2、字典Dictionary
字典就是一种COM对象,前期绑定使用方法,找到Microsoft Scripting Runtime,勾选后确定,然后我们就可以使用字典了:
代码语言:javascript复制Sub TestDic()
'声明
Dim d As Dictionary
'创建
Set d = New Dictionary
'释放
Set d = Nothing
End Sub
那我们如何能知道COM对象有些什么方法呢?还记得F2打开的对象浏览器吧,一旦我们引用了这个COM对象,在对象浏览器里我们就可以查看它了。
我们可以看到,其实这个库里面不止字典一个对象,还有些其他的,我们这次只看字典,可以看到他的方法有6个(绿色图标),属性有4个(灰色图标,蓝色那个是特殊的缺省属性,就像Range的Value属性,意思就是不写属性名的时候,默认就是它),总共10个东西,看起来还是挺简单的。
字典的方法、属性简单介绍:
- 我们前面说了,字典最大的功能就是能够快速的查找到需要的东西,从里面的名称你应该能猜到,Exists就是判断某个东西是否存在于字典里面。
- 而在判断是否存在之前,显然,我们需要先把数据装进去,很明显Add就是把数据装进去的方法。
- 有添加自然也就会有删除,Remove就是删除某个数据,而RemoveAll显然就删除全部了,相当于把字典初始化了。
- Count:很好理解,字典里存在多少个数据。
- CompareMode:是设置文本的对比方式的,主要就是是否区分大小写。
- Key、Keys:我们可以这样理解,字典,它真的很像我们使用的字典,比如汉字的新华字典,它的功能也是让我们快速查到需要的字,汉字的新华字典有一个可能我们没有在意过的特点,字在字典里是唯一的(多音字那些也是不同的字),也就是我们这个COM字典的重要特点,Key是唯一的,Add添加的就是这个Key,字典内部是不会有重复的Key的。Keys显然就是字典里的所有Key的集合,也就是一个数组了。
- Item、Imtes:汉字的新华字典每一个字,都对应了一种对这个字的解释说明,这个解释说明显然是可能重复的。字典在添加Key的时候,同时也要指定这个Key所对应的Item。Items也就是Item的集合。
3、使用
代码语言:javascript复制Sub TestDic()
'声明
Dim d As Dictionary
'创建
Set d = New Dictionary
Dim arrA() As Variant
Dim arrC() As Variant
Dim rowA As Long
Dim rowC As Long
Dim i As Long, j As Long
'获取A列和C列的最后一行行号
rowA = Cells(Cells.Rows.Count, 1).End(xlUp).Row
rowC = Cells(Cells.Rows.Count, 3).End(xlUp).Row
'将A列和C列的数据存放到数组中
arrA = Range("A1").Resize(rowA, 1).Value
arrC = Range("C1").Resize(rowC, 1).Value
'将A列数据记录到字典中
For i = 2 To rowA
d.Add arrA(i, 1), i
Next
'声明存储结果的数组
Dim result() As Variant
'数组使用一定要明确定义大小,结果数组肯定不会超过C列的数据数量
ReDim result(1 To rowC, 1 To 1) As Variant
'记录标题
result(1, 1) = arrC(1, 1)
'记录结果数据的个数
Dim resultCount As Long
resultCount = 1 '标题占用1个
'用循环找出列C中不在列A中出现的数据
'数据是从第2行开始的
For i = 2 To rowC
'判断C列的数据在字典中是否出现了
'存在的情况Exists返回True,我们需要的不存在的,所以前面要加Not
If Not d.Exists(arrC(i, 1)) Then
'说明是在A列没有出现的数据,记录下来
resultCount = resultCount 1 '结果的数量增加1
result(resultCount, 1) = arrC(i, 1)
End If
Next
'输出结果
Range("E1").Resize(resultCount, 1).Value = result
'释放
Set d = Nothing
End Sub
有了字典,我们就不需要循环内部再加循环的去判断了,你可以多加些数据对比程序运行的速度,一定会很惊奇字典查找数据的速度。
最后推荐大家看一下这个帖子:
呼之即来,挥之即去:
http://club.excelhome.net/forum.php?mod=viewthread&tid=926188&ordertype=1&page=1