1、.常见字典用法集锦及代码详解前言凡是上过学校的人都使用过字典,从新华字典、成语词典,到英汉字典以及各种各样数不胜数的专业字典,字典是上学必备的、经常查阅的工具书。有了它们,我们可以很方便的通过查找某个关键字,进而查到这个关键字的种种解释,非常快捷实用。凡是上过 EH 论坛的想学习 VBA 里面字典用法的,几乎都看过研究过northwolves 狼版主、oobird 版主的有关字典的精华贴和经典代码。我也是从这里接触到和学习到字典的,在此,对他们表示深深的谢意,同时也对很多把字典用得出神入化的高手们致敬,从他们那里我们也学到了很多,也得到了提高。字典对象只有 4 个属性和 6 个方法,相对其它的
2、对象要简洁得多,而且容易理解使用方便,功能强大,运行速度非常快,效率极高。深受大家的喜爱。本文希望通过对一些字典应用的典型实例的代码的详细解释来给初次接触字典和想要进一步了解字典用法的朋友提供一点备查的参考资料,希望大家能喜欢。给代码注释估计是大家都怕做的,因为往往是出力不讨好的,稍不留神或者自己确实理解得不对,还会贻误他人。所以下面的这些注释如果有不对或者不妥当的地方,请大家跟帖时指正批评,及时改正。字典的简介字典(Dictionary )对象是微软 Windows 脚本语言中的一个很有用的对象。附带提一下,有名的正则表达式(RegExp)对象和能方便处理驱动器、文件夹和文件的(FileSy
3、stemObject )对象也是微软 Windows 脚本语言中的一份子。字典对象相当于一种联合数组,它是由具有唯一性的关键字(Key)和它的项(Item)联合组成。就好像一本字典书一样,是由很多生字和对它们对应的注解所组成。比如字典的“典”字的解释是这样的:“典”字就是具有唯一性的关键字,后面的解释就是它的项,和“典”字联合组成一对数据。2常用关键字英汉对照:Dictionary 字典Key 关键字Item 项,或者译为 条目字典对象的方法有 6 个:Add 方法、Keys 方法、Items 方法、Exists 方法、Remove 方法、RemoveAll 方法。Add 方法向 Dictio
4、nary 对象中添加一个关键字项目对。object.Add (key, item)参数object 必选项。总是一个 Dictionary 对象的名称。 key 必选项。与被添加的 item 相关联的 key。 item 必选项。与被添加的 key 相关联的 item。 说明如果 key 已经存在,那么将导致一个错误。常用语句:Dim d Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Athens“ d.Add “b“, “Belgrade“d.Add “c“, “Cairo“代码详解1、Dim d :创建变量,也称为声明变量。
5、变量 d 声明为可变型数据类型(Variant),d 后面没有写数据类型,默认就是可变型数据类型(Variant)。也有写成 Dim d As Object的,声明为对象。2、Set d = CreateObject(“Scripting.Dictionary“):创建字典对象,并把字典对象赋给变量 d。这是最常用的一句代码。所谓的“后期绑定” 。用了这句代码就不用先引用c:windowssystem32scrrun.dll 了。3、d.Add “a“, “Athens“:添加一关键字 ”a”和对应于它的项”Athens” 。 4、d.Add “b“, “Belgrade”:添加一关键字”b”
6、 和对应于它的项”Belgrade”。 5、d.Add “c“, “Cairo” :添加一关键字 ”c”和对应于它的项”Cairo” 。 3Exists 方法如果 Dictionary 对象中存在所指定的关键字则返回 true,否则返回 false。object.Exists(key)参数object 必选项。总是一个 Dictionary 对象的名称。 key 必选项。需要在 Dictionary 对象中搜索的 key 值。常用语句:Dim d, msg$ Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Athens“ d.Ad
7、d “b“, “Belgrade“d.Add “c“, “Cairo“If d.Exists(“c“) Thenmsg = “指定的关键字已经存在。“Elsemsg = “指定的关键字不存在。“End If代码详解1、Dim d, msg$ :声明变量, d 见前例;msg$ 声明为字符串数据类型(String),一般写法为 Dim msg As String。 String 的类型声明字符为美元号 ($)。2、If d.Exists(“c“) Then:如果字典中存在关键字”c”,那么执行下面的语句。3、msg = “指定的关键字已经存在。“ :把“指定的关键字已经存在。“字符串赋给变量 m
8、sg。4、Else :否则执行下面的语句。5、msg = “指定的关键字不存在。“ :把“指定的关键字不存在。“字符串赋给变量msg。6、End If :结束 If ElseEndif 判断。Keys 方法返回一个数组,其中包含了一个 Dictionary 对象中的全部现有的关键字。object.Keys( )其中 object 总是一个 Dictionary 对象的名称。常用语句:Dim d, k 4Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Athens“ d.Add “b“, “Belgrade“d.Add “c“, “
9、Cairo“k=d.KeysB1.Resize(d.Count,1)=Application.Transpose(k)代码详解1、Dim d, k :声明变量,d 见前例;k 默认是可变型数据类型(Variant)。2、k=d.Keys:把字典中存在的所有的关键字赋给变量 k。得到的是一个一维数组,下限为 0,上限为 d.Count-1。这是数组的默认形式。3、B1.Resize(d.Count,1)=Application.Transpose(k) :这句代码是很常用很经典的代码,所以这里要多说一些。Resize 是 Range 对象的一个属性,用于调整指定区域的大小,它有两个参数,第一个是
10、行数,本例是 d.Count,指的是字典中关键字的数量,整本字典中有多少个关键字,本例 d.Count=3,因为有 3 个关键字。呵呵,是不是说多了。第二个是列数,本例是 1。这样左边的意思就是:把一个单元格 B1 调整为以 B1开始的一列单元格区域,行数等于字典中关键字的数量 d.Count,就是把单元格 B1 调整为单元格区域 B1:B3 了。右边的 k 是个一维数组,是水平排列的,我们知道 Excel 工作表函数里面有个转置函数 Transpose,用它可以把水平排列的置换成竖向排列。但是在 VBA 中不能直接使用该工作表函数,需要通过 Application 对象的 Worksheet
11、Function 属性来使用它。所以完整的写法是 Application. WorksheetFunction.Transpose(k),中间的 WorksheetFunction 可省略。现在可以解释这句代码了:把字典中所有的关键字赋给以 B1 单元格开始的单元格区域中。Items 方法返回一个数组,其中包含了一个 Dictionary 对象中的所有项目。object.Items( )其中 object 总是一个 Dictionary 对象的名称。常用语句:Dim d, t Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Ath
12、ens“ d.Add “b“, “Belgrade“d.Add “c“, “Cairo“t=d.ItemsC1.Resize(d.Count,1)=Application.Transpose(t)代码详解51、Dim d, t :声明变量,d 见前例;t 默认是可变型数据类型(Variant)。2、t=d.Items :把字典中所有的关键字对应的项赋给变量 t。得到的也是一个一维数组,下限为 0,上限为 d.Count-1。这是数组的默认形式。3、C1.Resize(d.Count,1)=Application.Transpose(t) :有了上面 Keys 方法的解释这句代码就不用多说了,就
13、是把字典中所有的关键字对应的项赋给以 C1 单元格开始的单元格区域中。Remove 方法Remove 方法从一个 Dictionary 对象中清除一个关键字,项目对。object.Remove(key )其中 object 总是一个 Dictionary 对象的名称。key 必选项。key 与要从 Dictionary 对象中删除的关键字,项目对相关联。 说明如果所指定的关键字,项目对不存在,那么将导致一个错误。常用语句:Dim d Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Athens“ d.Add “b“, “Belgr
14、ade“d.Add “c“, “Cairo“d.Remove(“b”)代码详解1、d.Remove(“b”):清除字典中”b” 关键字和与它对应的项。清除之后,现在字典里只有 2 个关键字了。RemoveAll 方法RemoveAll 方法从一个 Dictionary 对象中清除所有的关键字,项目对。object.RemoveAll( )其中 object 总是一个 Dictionary 对象的名称。常用语句:Dim d Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Athens“ d.Add “b“, “Belgrade“d.
15、Add “c“, “Cairo“6d.RemoveAll代码详解1、d.RemoveAll:清除字典中所有的数据。也就是清空这字典,然后可以添加新的关键字和项,形成一本新字典。字典对象的属性有 4 个:Count 属性、Key 属性、Item 属性、CompareMode 属性。Count 属性返回一个 Dictionary 对象中的项目数。只读属性。object.Count其中 object 一个字典对象的名称。常用语句:Dim d,n% Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Athens“ d.Add “b“, “B
16、elgrade“d.Add “c“, “Cairo“n = d.Count代码详解1、Dim d, n% :声明变量, d 见前例;n 被声明为整型数据类型(Integer)。一般写法为 Dim n As Integer 。 Integer 的类型声明字符为百分比号 (%)。2、n = d.Count :把字典中所有的关键字的数量赋给变量 n。本例得到的是 3。Key 属性在 Dictionary 对象中设置一个 key。object.Key(key) = newkey参数:object 必选项。总是一个字典 (Dictionary) 对象的名称。 key 必选项。被改变的 key 值。 ne
17、wkey 必选项。替换所指定的 key 的新值。 说明如果在改变一个 key 时没有发现该 key,那么将创建一个新的 key 并且其相关联的 item 被设置为空。7常用语句:Dim d Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Athens“ d.Add “b“, “Belgrade“d.Add “c“, “Cairo“d.Key(“c“) = “d“ 代码详解1、d.Key(“c“) = “d“ :用新的关键字”d”来替换指定的关键字 ”c”,这时,字典中就没有关键字 c 了,只有关键字 d 了,与 d 对应的项是”C
18、airo” 。 Item 属性在一个 Dictionary 对象中设置或者返回所指定 key 的 item。对于集合则根据所指定的 key 返回一个 item。读 /写。object.Item(key) = newitem参数object 必选项。总是一个 Dictionary 对象的名称。 key 必选项。与要被查找或添加的 item 相关联的 key。 newitem 可选项。仅适用于 Dictionary 对象;newitem 就是与所指定的 key 相关联的新值。说明如果在改变一个 key 的时候没有找到该 item,那么将利用所指定的 newitem 创建一个新的 key。如果在试图
19、返回一个已有项目的时候没有找到 key,那么将创建一个新的 key 且其相关的项目被设置为空。常用语句:Dim d Set d = CreateObject(“Scripting.Dictionary“)d.Add “a“, “Athens“ d.Add “b“, “Belgrade“d.Add “c“, “Cairo“MsgBox d.Item(“c“) 代码详解1、d.Item(“c“) :获取指定的关键字 ”c”对应的项。 2、MsgBox :是一个 VBA 函数,用消息框显示。如果要详细了解 MsgBox 函数的,可参见我的另一篇文章“常用 VBA 函数精选合集” 。8http:/ 属
20、性设置或者返回在 Dictionary 对象中进行字符串关键字比较时所使用的比较模式。object.CompareMode = compare参数object 必选项。总是一个 Dictionary 对象的名称。 compare 可选项。如果提供了此项,compare 就是一个代表比较模式的值。可以使用的值是 0 (二进制) 、 1 (文本), 2 (数据库)。 说明如果试图改变一个已经包含有数据的 Dictionary 对象的比较模式,那么将导致一个错误。常用语句:Dim d Set d = CreateObject(“Scripting.Dictionary“)d.CompareMode
21、= vbTextCompared.Add “a“, “Athens“ d.Add “b“, “Belgrade“d.Add “c“, “Cairo“d.Add “ B “, “ Baltimore“代码详解1、d.CompareMode = vbTextCompare :设置字典的比较模式是文本,在这种比较模式下不区分关键字的大小写,即关键字”b”和”B”是一样的。 vbTextCompare 的值为1,所以上式也可写为 d.CompareMode =1 。如果设置为 vbBinaryCompare(值为 0) ,则执行二进制比较,即区分关键字的大小写,此种情况下关键字”b”和”B” 被认为是
22、不一样的。2、d.Add “ B “, “ Baltimore“ :添加一关键字”B”和对应于它的项”Baltimore” 。由于前面已经设置了比较模式为文本模式,不区分关键字的大小写,即关键字”b”和”B” 是一样的,此时发生错误添加失败,因为字典中已经存在”b” 了,字典中的关键字是唯一的,不能添加重复的关键字。实例 1 普通常见的求不重复值问题一、问题的提出:表格中人员有很多是重复的,要求编写一段代码,把重复的人员姓名以及重复的次9数求出来,复制到另一个表格中。如图实例 11 所示。论坛网址:http:/ 实例 1-1 二、代码:Sub cfz()Dim i UsedRange 为已经使
23、用的单元格区域。本句可解释为:清空第 3 行以下的单元格。3、a = Sheet1.Range(Sheet1.a4, Sheet1.i65536.End(xlUp) :把原始数据所在的表1 自 A4 以下的 I 列最后的非空单元格区域的值赋给变量 a。4、Set d = CreateObject(“scripting.dictionary“) :创建字典对象 d。5、ReDim b(1 To UBound(a), 1 To 8) :根据数组 a 的大小重新声明数组 b。6、For i = 1 To UBound(a) :在 1 和数组 a 第一维的上界值之间逐一循环。7、ss = a(i, 1
24、) & a(i, 2) & a(i, 4) & a(i, 5) & a(i, 6) & a(i, 8) :把多个条件比例、位置、项25目名称、大系统编号、小系统编号和相同楼层数用连接符号&连成一个字符串,然后赋给变量 ss。8、If Not d.Exists(ss) Then :IfThen 结构利用了字典的 Exists 方法和 Not 来判断:如果字典 d 里面不存在 ss 表示的关键字,那么执行下面的语句。9、n = n + 1 :把变量 n 增加 1 以后仍然赋给 n。10、d.Add ss, n :把 ss 的值作为关键字,n 的值作为对应的项一起加入字典 d 中。n 的值实际是关键
25、字的位置次序,如 n=1 时是第一个关键字;n=2 时是第二个关键字。11、b(n, 1) = a(i, 2): b(n, 2) = a(i, 5): b(n, 3) = a(i, 6): b(n, 4) = a(i, 4) :为了使代码看起来简短一些,可以用冒号”:”把多个语句连成一行。4 个语句分别给数组 b 的各个元素赋以对应的值。12、b(n, 5) = a(i, 1): b(n, 6) = a(i, 8): b(n, 7) = a(i, 9) :与上述的 11 条相同。13、否则执行这句:b(d(ss), 7) = b(d(ss), 7) & “+“ & a(i, 9) :d(ss)
26、等于关键字对应的项,在本例里等于对应的 n 的值。本句是把图纸长度 a(i, 9)用“+“连起来赋给数组b,这样就得到了长度明细一栏数据。14、For i = 1 To d.Count :在字典关键字数目中逐一循环。15、x = Split(b(i, 7), “+“) :运用 VBA 函数 Split 把 b(i, 7)(长度明细)按照“+“ 分割,返回一个下标从零开始的一维数组 x。如果要详细了解 Split 函数的,可参见我的另一篇文章“常用 VBA 函数精选合集” 。http:/ j = 0 To UBound(x) :在上面的 x 数组之间逐一循环。17、w = w + x(j) :把
27、变量 w 加 x(j)数组的一个元素以后仍然赋给 w。实际得到 x数组的累加值。18、b(i, 8) = b(i, 5) * b(i, 6) * w / 100: w = 0 :w 求出后经过按要求计算得到的值赋给数组 b 的第 8 列元素。 (数量列)另一句把变量 w 置 0。避免在新一次的循环中误加进去。19、b4.Resize(n, 8) = b :最后把数组 b 赋给 B4 开始的单元格区域。代码执行后如图实例 6-1 所示。26图 实例 6-1 示例实例 7 字典法排序一、问题的提出:A 列 B 列是按顺序排列的全部股票代码和股票名称,C 列 D 列和 E 列 F 列是另外按条件筛选
28、出来的无序的数据, 要求编写一段代码,将它们排列到与 A 列相同的股票行里面。代码执行前如图实例 7-1 所示。27图 实例 7-1 示例二、代码:Private Sub CommandButton1_Click() by:oobirdDim d As Object, rng, i%, j%, arrSet d = CreateObject(“Scripting.Dictionary“)rng = Range(“a3:f“ & a65536.End(xlUp).Row)ReDim arr(1 To UBound(rng), 1 To 4)For i = 1 To UBound(rng) d(C
29、Str(rng(i, 1) = iNext iFor j = 3 To 5 Step 2For i = 1 To Cells(65536, j).End(xlUp).Row - 2If d(CStr(rng(i, j) “ Then :rng(i, j)是 C 列或者 E 列的股票代码,本句是如果这个股票代码关键字对应的项不等于空的时候,执行下面的代码。10、arr(d(CStr(rng(i, j), j - 2) = rng(i, j) :d(CStr(rng(i, j)=i 见上述 6 的解释,表示数组 arr 的第 1 维,相当于行; j-2 是随着 j=3 的时候,j-2=1;j=5
30、的时候 j-2=3,相当于数组列的参数。把相应的股票代码赋给相同股票代码的第 1 列或者是第 3 列。11、arr(d(CStr(rng(i, j), j - 1) = rng(i, j + 1) :把相应的股票名称赋给相同股票代码的第 2 列或者是第 4 列。12、c3.Resize(UBound(rng), 4) = arr :把数组 arr 赋给 C3 开始的单元格区域。代码执行后如图实例 7-2 所示。29图 实例 7-2 示例实例 8 2 级动态数据有效性问题一、问题的提出:A 列是源名称,中间有空格, B 列为各个源名称对应的数目不同的代号,C 列是目标名称来源于源名称,要求在 C
31、 列设置不重复的、没有空格的数据有效性供选择;同时D 列目标代号,要求随着 C 列选择的目标名称的不同,提供对应的代号供选择,是为第2 级数据有效性。代码执行前如图实例 8-1 所示。30图 实例 8-1 示例二、代码:Private Sub Worksheet_SelectionChange(ByVal Target As Range)If Target.Count 1 Then Exit SubIf Target.Column 3 Then Exit SubDim d, i&, Myr&, Arr, r%, Arr1(), cp$, ks&, js&, j&Set d = CreateObject(“Scripting.Dictionary“)Myr =b65536.End(xlUp).RowArr = Range(“a2:b“ & Myr)If Target.Column = 3 ThenFor i = 1 To UBound(Arr)If Arr(i, 1) “ Thend(Arr(i, 1) = “End IfNextWith Target.Validation.Delete