Excel VBA 编程基础 -- 结构化数据类型(七)- 集合(二)
我们说过,数组是由多个同类型的元素组成的集合。我们已经见过整型数组、字符串数组,当然集合也可以作为数组的元素。我们已经讨论过使用 UDT 作为数组元素读取这个数据集,现在我们来看一下如何使用集合作为数组元素读取这个数据集,代码如下图所示:首先,声明一个集合类型的变量 myC,一个集合类型的动态数组 myA,以及两个长整型变量 row 和 size。然后,通过Excel 函数 CountA 获取数据集的行数(包括表头),并根据数据集行数分配数组空间(ReDim)。接下来,从第二行开始循环,一直到遇到空单元格为止。在循环体内,每循环一次,都使用 Set myC = New Collection 实例化一个 Collection 类型的对象,并使用 Add() 方法向 myC 集合中添加元素,元素使用 Key/Item 方式添加,以便后续访问。集合构造完成以后,将集合变量赋给数组,作为数组的一个元素,然后递进到下一行。循环完成以后,整个数据集都读入到数组 myA 中。用一个 For ... Next 循环打印数组元素。仍然是图1的数据集,其中有些同名记录,下面我们来看如何利用集合来剔除数据集中的同名记录,代码如图3所示:原始数据集有 10 万条记录,去重后剩余 93700 条。去重的基本思路是利用集合中的键值(Key)唯一性原理,将 name 列作为集合的 Key,遇到同名记录,就会出错。通过判断 Err 对象的 Number 属性,不为 0 即发生错误,说明当前行的 name 列与 myC 中的 Key 冲突,所以删除当前行(用 Range 对象的 Delete 方法),同时 row 减 1,并清除 Err 对象中的 Number 属性值。然后,递进到下一行(对于发生错误的情况,如上面所说明的,row 已经减 1,此时再加 1,说明下一次循环要处理的行是被删除行的下一行),循环处理。这里面的关键是 On Error Resume Next 语句,这个语句告诉 VBA,发生错误的话,继续执行下一行(如上面所说明的,进行错误处理)。如果没有这条语句,一旦遇到同名记录,执行就会中断,并显示错误信息。Collection 没有提供判断某个 Key 是否已经存在的函数,我们可以利用 VBA 的这种错误处理机制自己写一个实现类似功能的函数 KeyExists:Function KeyExists(C As Collection, K As String) As Boolean On Error Resume Next IsObject(C(K)) If Err.Number <> 0 Then KeyExists = False Err.Clear Else KeyExists = True End IfEnd Function
如果 K 不在集合 C 中,访问 C(K) 就会发生错误。如果没有发生错误,说明 K 在集合 C 中。有了函数 KeyExists(),我们可以重写上面的数据集去重代码,如图4所示:图4 利用函数 KeyExists() 重写数据集去重代码集合有键有值,是一个轻量型的字典。VBA 中的集合(Collection)与 Delphi 中的集合(Set)不是一个概念。Delphi 中的 Set 是数学上的集合概念在计算机语言中的实现,VBA 中的 Collection 就是一个轻量型的字典,可以按键(即名字)访问,这在有些情况下比数组只能按位置访问要方便得多。这就是 Collection 存在的意义。