字典与集合(Dictionary与Collection)
Dictionary对象将替换Collection对象,并提供附加的语言从而使增加和删除记录的速度比以前提高三倍
虽然Visual Basic 6.0只有很少的新特点,但是具有某些功能强大的新的对象模型,其中之一就是Dictionary对象。
Dictionary对象是无处不在的Visual Basic Collection对象的新版本。它的介绍存在于VBScript 2.0,并通过Visual Basic 6.0 对Scripting Runtime Library的支持涉入Visual Basic的全部内容。刚开始,Dictionary对象仅仅包含在VBScript中,并作为Perl相关内容的等价体对Web组请求进行答复。
与Collection对象相似,你能够通过Dictionary存储任何类型的数据或字典对象,这些数据和对象通常被看作字典的组成部分,每一部分都被赋予字符串型键值。虽然我不认为Microsoft意图使你完全摆脱收集和替换上述数据和对象的烦恼,但是实际上,在先前的Visual Basic 6.0文档中,对Dcitionary对象确实很少提及,因此我认为这是Visual Basic 6.0的一个最新的重要特点。
Dictionary对象与Collection对象的比较
从Visual Basic 4.0开始,Collection对象就作为主要的数据类型替代了用户自己定义的类型,由此以后,大多数Visual Basic程序都包含Collection对象。如果你从Visual Basic 4.0开始已经非常习惯于使用Collection对象,那么你又为什么需要作出改变呢?这主要有几个因素:
Dictionary对象比Collection 对象更快,这种速度优势主要体现在增加数据成员、在字典中进行迭代搜索和删除数据成员上。
Dictionary对象包括那些你经常不得不自己编制的封装函数,例如Exists函数和RemoveAll函数。
Dictionary对象让你能够创建Key值数组和Item值数组,从而加快在字典中进行迭代搜索的速度。
Dictionary对象让你能够覆盖已经存在的Key值和已经存在的数据成员。 Dictionary对象还确实存在着下述缺点,但它们本身并不值一提:
与Collection对象不同,Dictionary对象不是VBA语言DLL的一部分,这意味着你需要借助SCRRUN.DLL,并将之连接到相应的应用程序。
Dictionary对象实现For…Each…Next循环的方法也很奇怪,它不是返回Item值,而是返回Key值。
Dictionary对象还有一恼人之处,就是如果你想从字典中删除一个没有搜索到的成员,你就必须添加数据到这个空的条目或不存在的键。
访问Dictionary对象正如我先前所说,Dictionary对象不是VBA或Visual Basic实时语言的具体存在的部分,它是存在于Microsoft Scripting Runtime Library(SCRRUN.DLL)中的一个对象。为了在应用程序中使用Dictionary对象,就必须利用Reference对话框增加一个项目级的引用到Scripting Runtime Library。
增加完引用之后,创建Dictionary对象的实例,如下:
Dim oDict As Dictionary
Set oDict = New Dictionary
' Do some work.
Set oDict = Nothing
为了增加一个成员到Dictionary对象,利用Add方法,其中包括两个参数:需要增加的数据和与数据相关联的字符串型Key值,语法如下:
dictionary.Add Key, Data
在Dictionary对象中没有指明新的数据成员存放位置的参数,它将由字典自己挑出。你还需要注意Add方法的参数正好与Collection对象的Add方法相反,在Collection对象 中:
collection.Add Data, [Key], [before], [after]
与Collection对象类似,Dictionary对象的成员能够是任何数据类型、对象或其他字典,从而使你能够按照自己的意愿任意嵌套Dictionary对象。
访问Dictionary对象的成员
Dictionary对象的Item方法是访问包含在字典中数据的推荐方法,其好处是速度快,非常快。我所做的测试表明,访问Dictionary对象数据成员的速度要比访问Collection对象数据成员的速度快三倍。如果你打开对象浏览器,选择Dictionary对象,并观察隐藏的成员,你就会看到名为HashVal的属性,这表明Dictionary对象存在无用信息列表和一些奇怪的排队算法。
在设计Dictionary对象时,主要是利用将字符串型Key值作为一个参数传递给Item的方法来实现对数据的访问,这一点与Collection对象相似,例如,你可以利用:
VItem = oDictionary.Item(sKey)
这儿警告一句,如果试图利用一个并不存在的键值返回Collection成员的数值,将会出错(code 5, Invalid Procedure Call or Argument)。
Dictionary对象并不这样,它在插入该新成员时,采用并不存在的键值对应某个键同时用零长度字符串对应数据成员。Dictionary对象总是检查你要使用的键是否存在于字典内,可以想象,这一特点能够轻易地捕捉不经意所犯的错误,至于检查键值存在性的方法将在本文的后续内容中述及。
当使用Collection对象时,你不能直接顺序地访问字典中的数据,但是使用字典的Item方法时就不这样,你能够快速地创建所有数据成员的数组,并利用该数组顺序地访问所有数据:
Dim vItems As Variant
Dim iOrdinal As Integer
iOrdinal = 10
vItems = oDictionay.Items
vItem = vItems(iOrdinal)
从Collection对象中删除数据的方法通常是采用For…Each…Next语句,在你初次对Dictionary对象使用For…Each…Next时,可以假设你从未对字典使用过该语句,但是尽管没有当前的记录位置,你仍能够使用For…Each…Next,你只需要Dictionary对象的inter_NewEnum函数返回的与条目有关的键值,而不是象Collection对象那样,需要返回字典条目的索引,你可以将这些键值传递给Item方法以便删除数据成员,如下所示:
Dim sKey As Variant
For Each sKey in oDictionary
VItem = oDictionary.Item(sKey)
…
Next
当你在封装类中利用Dictionary对象时,存在另一个使用For…Each…Next的次要关键。你不能在客户端使用For…Each…Next循环对数据成员进行迭代搜索,除非你愿意进行大量的复杂编程。其原因是Dictionary对象的internal_NewEnum函数不是一个隐含成员,而在Collection对象中它是,它不能通过Visual Basic调用,因此你不能够在封装类实现自己的_NewEnum函数,简单的Set NewEnum = mCol.[_NewEnum]语句不能与Dictionary对象共同工作,但是,使用Dcitionary对象获得的诸多好处使这种折中非常值得。
那么,怎样访问Dictionary对象封装类的每一个成员呢?Dictionary对象包含名为Items的方法,该方法返回所有Dictionary对象成员的一个可变数组,你只需要在自己的类中提供一个封装子程序以返回Item数组:
Public Property Get Items() As Variant
Items = mdDict.Items
End Property
或者你愿意提供一个更加有意义的名字给封装特性,那么可以这样:
Public Property Get Employees() As Variant
Employees = mdDict.Items
End Property
然后你的客户端程序代码就可以利用For…Each…Next或For…Next循环在可变数组中进行迭代搜索,以下这些代码告诉你怎样才能实现这一点:
Dim oEmployees As Employees ' wrapper class
Dim aEmployees As Variant ' Variant to hold array
Dim oEmp As Employee ' data member class
Dim i As Integer ' simple counter
Set oEmployees = New Employees 'Dictionary wrapper class
aEmployees = oEmployees.Employees 'return an array of objects
For i = lBound(aEmployees) To uBound(aEmployees)
Set oEmp = aEmployees(i)
cboNames.AddItem oEmp.Name
Set oEmp = Nothing
Next i
Set oEmployees = Nothing
那么性能怎样呢?当在同样的机器上调用动态连接库时,结合Dictionary封装类的Item数组和Foe…Each…Next的迭代搜索不如仅仅运用Collection封装类进行的迭代搜索快,但是如果你处理的是远程或进程外的服务程序,那么情况刚好相反。利用Dictionary的封装类,你只是进行简单数组的简单转换,而Collection类则反复调用远程服务程序,每一个迭代都要进行过程调用。
我设置了一个简单的实验以考察远程Dictionary对象和Collection对象的迁移性,这些对象包括1000个简单的字符串成员并利用它们迁移一个客户端Form的列表,Dictionary对象迁移该列表只需要四分之一秒,而Collection对象迁移该列表则耗费了差不多三秒钟。
你的成员存在吗?
我反复抱怨Collection对象的一个因素是其没有能力让你预先知道Collection对象的某一个成员是否存在,如果该成员的键值并不存在,那么你就不得不处理出现的错误。由于这个原因,我通常利用一个类来封装我的Collection对象成员,并使它们包括Exists属性。
不管怎样,Microsoft使Dictionary对象具有Exists方法。Exists非常便于使用,并返回True或False,如下所示:
If oDictionary.Exsits(sKey) Then
' The key is there .
vVal = oDictionary.Item(sKey)
Else
MsgBox "The key doesn't exist"
End If
由于Dictionary对象总是为成员添加一个键值和一个空字符串,所以当你试图返回一个并不存在键值的条目时,你总是能够在返回该条目之前利用Exists方法来检测它的存在性(如上面例子所示),这个特点使你免于直接访问一个并不存在的键值。
键值覆盖
如果你曾经试图改变某个与Collection对象成员对应的键值,那么你知道这不可能。当对象成员加入到Collection对象时,该成员的数据和键值就已经被固定下来了。你能做的唯一选择就是使用Remove方法清除该成员并增加一个新成员到该对象。但是,你能够利用Dictionary对象的Key特性来覆盖该键的键值,如下例所示:
If oDictionary.Exists(sOldKey) Then
' The key is there .
oDictionary.Key(sOldKey) = sNewKey
Else
MsgBox "The key dosen't exsit"
End If
成员覆盖
我猜想Microsoft在编制Collection对象时,他们假设Collection对象的成员一旦加入就不再改变,他们为什么会认为开发人员仅仅与静态数据打交道呢?!因此,改变Collection对象成员的唯一办法就是先从Collection对象中删除它们并重新加入。
与Key特性相似,你能够利用存在于表达式两边的Dictionary对象的Item特性。在一个表达式的右边,你返回对象成员的值,而在表达式的左边,你可以设置成员的值,方法如下:
If oDictionary.Exists(sKey) Then
' The key is there .
oDictionary.Item(sKey) = vNewItem
Else
MsgBox "The key doesn't exist"
End If
补充
当你需要字典内所有键值的数组时,Item方法和Key方法也能够帮助你。Item方法可以返回包含字典内所有数据成员的可变数组,而Key方法则可以返回包含字典内所有键值的可变数组。 Dictionary对象的其他特性包括返回字典内成员数目的Count特性和能够让你控制内部搜索执行情况的CompareMode特性,还有Remove特性和RemoveAll特性,正如其名字所示,它们用于清除字典内的数据成员。
总结
Dictionary对象与Collection对象相比,是一个非常有价值的尝试。它不但速度快,而且具有许多特性,使你从原来不得不自己编制封装类的烦恼中解脱出来。虽然用Dictionary对象替换Collection对象还需要一些次要的记录技术(根据For…Each…Next等而定),但是利用Dictionary对象所带来的性能上的提高足以补偿这些努力。本专题的PROFESSIONAL RESOURCE CD包含一
个例子类,从而向你展现怎样围绕Dictionary对象创建一个名为DictCLass.CLS的封装类,它还包括一个例子应用程序,该例子向你展示怎样利用这些类来获得超出于你应用程序的强大功能。
Collection相当普及,大部分Visual Basic数据类都源于此类,而Dictionary对象是重要的改进,在添加和删除对象成员方面要比Collection对象快三倍,你能够戏剧性地提高应用程序的性能。你也可以自己进行Dictionary对象和Collection对象的性能测试比较,你会得到与我大致相同的结果。
如果我可以自由选择(我的客户有足够的时间和金钱),那么我将用Dictionary对象替换所有的Collection对象。这项工作还没有开始,至少本周不会进行,但是从现在开始,我用Visual Basic 编制的所有程序都将采用Dictionary对象。
字典与集合(Dictionary与Collection)的更多相关文章
- Python中的字典与集合
今天我们来讲一讲python中的字典与集合 Dictionary:字典 Set:集合 字典的语法: Dictionary字典(键值对) 语法: dictionary = {key:value,key: ...
- 字典集合Dictionary<K,V>和构造的应用==>>体检套餐项目
效果 首先,我们先来准备我们需要的类 1.检查项目类 using System; using System.Collections.Generic; using System.Linq; using ...
- C#在foreach循环中修改字典等集合出错的处理
C#在foreach循环中修改字典等集合出错:System.InvalidOperationException: Collection was modified; enumeration operat ...
- 字典,字符串,元组,字典,集合set,类的初步认识,深浅拷贝
Python之路[第二篇]:Python基础(一) 入门知识拾遗 一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. if 1==1: name = 'Jaso ...
- python基础知识3——基本的数据类型2——列表,元组,字典,集合
磨人的小妖精们啊!终于可以归置下自己的大脑啦,在这里我要把--整型,长整型,浮点型,字符串,列表,元组,字典,集合,这几个知识点特别多的东西,统一的捯饬捯饬,不然一直脑袋里面乱乱的. 一.列表 1.列 ...
- Python中字典和集合
Python中字典和集合 映射类型: 表示一个任意对象的集合,且可以通过另一个几乎是任意键值的集合进行索引 与序列不同,映射是无序的,通过键进行索引 任何不可变对象都可用作字典的键,如字符串.数字.元 ...
- 6 字典和集合——《Swift3.0从入门到出家》
字典和集合 字典 字典是集合类型存放多个键值对,其中键是唯一的,不能重复 字典中存放的键值对是无序的,写入的顺序和读取的顺序可能不同 字典中存放的数据是任意类型 字典可以分为可变字典和不可变字典 创建 ...
- Welcome-to-Swift-04集合类型(Collection Types)
Swift提供了两种集合类型来存放多个值——数组(Array)和字典(Dictionary).数组把相同类型的值存放在一个有序链表里.字典把相同类型的值存放在一个无序集合里,这些值可以通过唯一标识符( ...
- Python中列表,元组,字典,集合的区别
参考文档https://blog.csdn.net/Yeoman92/article/details/56289287 理解Python中列表,元组,字典,集合的区别 列表,元组,字典,集合的区别是p ...
- [19/09/19-星期四] Python中的字典和集合
一.字典 # 字典 # 使用 {} 来创建字典 d = {} # 创建了一个空字典 # 创建一个保护有数据的字典 # 语法: # {key:value,key:value,key:value} # 字 ...
随机推荐
- NetBeans无法使用编码GBK安全地打开该文件 解决方法
正常安装的NetBeans在打开UTF-8编码的文件时,会提示“NetBeans无法使用编码GBK安全地打开该文件”,点击“是”强制打开后,中文会变成乱码. 上述问题可以通过如下方式解决: 用文本编辑 ...
- (转载)div最小宽度和自适应的实现方法
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- srpm包的编译方式
基本说明:后缀仅为rpm的包如xxxxx.rpm称作为二进制包 ------ 可以直接安装到架构匹配的系统上; 后缀为src.rpm的包如webkitgtk-2.4.7-1.fc21.src.rpm称 ...
- IOS中扩展机制Category和associative
在ios开发中,有时候会遇到以下的问题,需要在一个类中添加自己的一些属性和方法.一般的做法是重写一个类来继承它,但是有时候就只是需要添加一些简单的属性和方法,那么这样做就显得过于麻烦,其实在IOS中还 ...
- CSU 1160(进制问题)
CSU 1160 Time Limit:1000MS Memory Limit:131072KB 64bit IO Format:%lld & %llu Descrip ...
- NET Core 数据保护2
ASP.NET Core 数据保护(Data Protection 集群场景)[下] 前言 接[中篇],在有一些场景下,我们需要对 ASP.NET Core 的加密方法进行扩展,来适应我们的需求, ...
- 构建高可用web站点学习--前言
前言:本人对于提高web站点的访问量等的有很浓厚的兴趣,也学习了将近一年的时间,希望能总结点东西,虽然很多东西都是从书籍和资料中学习的,而不是原创,但是这是我总结的一点感悟和进行的分类吧.而且可能思路 ...
- 无聊时,可以去HASKELL里找点感觉
可以和C,JAVA,PYTHON作任意的比较,感觉越来越晰一些计算机语言里深层的东东... doubleMe x = x + x doubleUs x y = x * + y * doubleSmal ...
- MYSQL用SOURCE命令时导入乱码的问题解决
现在遇到了,但记得上次辉哥说过的方法,在MYSQL命令行里输入: set names utf8; 再执行SOURCE命令,搞定!
- 测试Flask+PYTHON的WEB框架
参数URL: http://blog.csdn.net/qwiwuqo/article/details/8970621 安装flask之前,你必须要先安装python和easy_install. 安装 ...