ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 23822|回复: 26

[转帖] 字典与集合(Dictionary与Collection)

[复制链接]

TA的精华主题

TA的得分主题

发表于 2007-9-8 12:04 | 显示全部楼层 |阅读模式
[转帖] 字典与集合(Dictionary与Collection)

转自http://bbs.cst.sh.cn/cgi-bin/bbs/bbsanc?path=/groups/GROUP_3/Programming/DB7B684CC/A4C14CB41

发信人: nicebean (阿罡), 信区: Programming
标  题: 利用VB 6.0 中Dictionary对象的强大功能
发信站: 生命玄机 (Tue Feb 29 12:47:34 2000), 站内信件

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对
象。

TA的精华主题

TA的得分主题

发表于 2007-9-8 19:52 | 显示全部楼层

内行!就是缺少一些技巧性的东东!

TA的精华主题

TA的得分主题

发表于 2007-9-8 20:16 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2007-9-8 21:25 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册

先收下了。

谢谢哈^_^

TA的精华主题

TA的得分主题

发表于 2007-9-8 21:26 | 显示全部楼层

这个转贴文中作者开始的某些地方有“基础的常识性错误”

你们所要讨论的Dictionary对象来自于Script Runtime对象模型,而不是Visual Basic 6.0,所以,VB6的文档是不会提及Dictionary对象的(正如EXCEL文档中,如果你只查询“纯粹的”VBA语法,在CHM文档中不会涉及EXCEL APPLICATION、WORKBOOK、WORKSHEET、RANGE、CELL对象和事件一样)

不过他后面的大部分资料是正确的,比如Script Runtime来自SCRRUN.DLL——但记住,这个东西不是来自VB系统,如果我没有记错,MS这个Script Runtime在Visual Studio 6(就是VB6所属的这套开发套件)之后才出现,它相关的资料未列举在VISUAL STUDIO 6的帮助MSDN98中

Script Runtime本身顾名思义,就是用于脚本管理的自动化对象,由于是自动化对象(AUTOMATION),也可以用在任何支持自动化动象的语言,如ASP、JS、VBS、OFFICE、VB、VFP中,相关的标准所有对象列表、事件、方法及属性帮助,除了MSDN ONLINE之外,我记得在WSH的文档中也有,比如下载微软的Windows Script V5.6 文档.chm

Script Runtime系列还有另一个更有名的对象,就是文件系统对象FSO(Scripting.FileSystemObject),在这个论坛上也常有人使用——虽然EXCEL和VBA自身也提供有传统的文件函数和语句,但面向对象的FSO看上去“更好用更易于理解”——它可以处理文件、文本文件流(缺点是不能处理二进位数据和随机文件)、文件夹,但同样不属于EXCEL和VB6

TA的精华主题

TA的得分主题

发表于 2007-9-8 23:10 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
学习了。好。

TA的精华主题

TA的得分主题

发表于 2007-9-9 08:28 | 显示全部楼层
ldy888楼主强啊!而 hiyou (无冕之王)更强!!!两高手的文章我都复制下来留着慢慢“消化”!谢谢二位高手的指教!!!

TA的精华主题

TA的得分主题

发表于 2007-9-9 11:05 | 显示全部楼层
QUOTE:
以下是引用hiyou在2007-9-8 21:26:14的发言:

这个转贴文中作者开始的某些地方有“基础的常识性错误”

你们所要讨论的Dictionary对象来自于Script Runtime对象模型,而不是Visual Basic 6.0,所以,VB6的文档是不会提及Dictionary对象的(正如EXCEL文档中,如果你只查询“纯粹的”VBA语法,在CHM文档中不会涉及EXCEL APPLICATION、WORKBOOK、WORKSHEET、RANGE、CELL对象和事件一样)

不过他后面的大部分资料是正确的,比如Script Runtime来自SCRRUN.DLL——但记住,这个东西不是来自VB系统,如果我没有记错,MS这个Script Runtime在Visual Studio 6(就是VB6所属的这套开发套件)之后才出现,它相关的资料未列举在VISUAL STUDIO 6的帮助MSDN98中

Script Runtime本身顾名思义,就是用于脚本管理的自动化对象,由于是自动化对象(AUTOMATION),也可以用在任何支持自动化动象的语言,如ASP、JS、VBS、OFFICE、VB、VFP中,相关的标准所有对象列表、事件、方法及属性帮助,除了MSDN ONLINE之外,我记得在WSH的文档中也有,比如下载微软的Windows Script V5.6 文档.chm

Script Runtime系列还有另一个更有名的对象,就是文件系统对象FSO(Scripting.FileSystemObject),在这个论坛上也常有人使用——虽然EXCEL和VBA自身也提供有传统的文件函数和语句,但面向对象的FSO看上去“更好用更易于理解”——它可以处理文件、文本文件流(缺点是不能处理二进位数据和随机文件)、文件夹,但同样不属于EXCEL和VB6

1、Dictionary对象来自于Script Runtime对象模型没错,但不属于 Visual Basic 6.0 则实在勉强,按这个逻辑ListView也不属于 Visual Basic 6.0。其实basic是个筐,只要理解了部件这个概念,就不会纠缠于这个属于哪个,那个属于这个了!


2、MSDN98 vb文档中对 Dictionary 作了详细的介绍,并明确用 Dictionary 取代 Collection。

3、理解的错误谁也难免,但是不知道就说,会害了好多人!共勉!

TA的精华主题

TA的得分主题

发表于 2007-9-9 11:59 | 显示全部楼层

未消化,先顶下

习惯了用集合中的一些功能(尤其是不重复)

要转过来用字典,还是需要一些基本的理论的

谢了

TA的精华主题

TA的得分主题

发表于 2007-9-9 12:20 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
QUOTE:
以下是引用丸究阵引在2007-9-9 11:05:58的发言:

1、Dictionary对象来自于Script Runtime对象模型没错,但不属于 Visual Basic 6.0 则实在勉强,按这个逻辑ListView也不属于 Visual Basic 6.0。其实basic是个筐,只要理解了部件这个概念,就不会纠缠于这个属于哪个,那个属于这个了!


2、MSDN98 vb文档中对 Dictionary 作了详细的介绍,并明确用 Dictionary 取代 Collection。

3、理解的错误谁也难免,但是不知道就说,会害了好多人!共勉!

查了一下,VB6和VC6中有SCRRUN.DLL的发布包,MSDN98 VBCON98.CHM中有FSO和Dictionary的相关链接

SORYY,确实是我记错了,因为SCRIPTING RUNTIME 在WIN98以后开始是WINDOWS系统自带的,之前的系统没有(如WINNT),VS6套件中,VB6和VC6可以在发布时对未配置SCRRUN的系统安装上述组件,可视为同一套

很抱歉,这次犯了常识性错误的是我了,MSDN98都没有细查......以上

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-15 10:18 , Processed in 0.053664 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表