ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[原创] VBA中ArrayList使用之浅见

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2020-8-20 20:25 | 显示全部楼层 |阅读模式
本帖最后由 lmgz007 于 2020-8-21 10:58 编辑

引子:
最近接触到了ArrayList,感觉非常好用。但可能因为比较偏门的缘故,网上关于ArrayList在vba中使用的文字极少,本站也没有。源头文章仅找到1篇(链接附后),虽有读者对其进行了加工和补充,但依然不够完善。其他文章多不是vba中使用,且以解析原理为主。经过研究和比较,特写此文,和大家交流学习,不足之处请大家批评指正。(所有测试都在Excel 2019中完成)

前言:
ArrayList就是动态数组,用MSDN中的说法,就是Array的复杂版本。在VBA中,ArrayList提供了丰富的功能,包括排序、数组转换、动态的增加和减少元素、删除所有元素项目等。

相比字典,ArrayList的优势有:可以写入重复的item,并可查找;可以在指定索引位置插入item;可以选择对item进行排序或不排序(包括去重排序);可以通过item或索引删除(排序前排序后都可以);
劣势则是对大量数据的处理效率不够高。

相比SortedList,优势有:可以写入重复的item;可以不排序。

相比一般的数组,优势是可以排序,操作简单,上手容易。

内容:
ArrayList的使用非常简单,大概可分为以下几个部分:
1.创建ArrayList
2.添加或插入item
3.查找或删除item(可清空所有数据)
4.排序
5.复制
6.输出(可转数组)
7.释放(删除)arrList

通常必要的部分是1,2,6,其他部分可自由选择与组合使用。


内容解读:

1.创建ArrayList
1.1 前期绑定
单击“工具——引用”,在“引用”对话框中,找到并选中mscorlib.dll前的复选框,确定。然后用代码声明:
Dim arrlist As New arraylist

或者:
Dim arrlist As ArrayList
Set arrlist = New ArrayList

1.2 后期绑定
Dim arrList As Object
Set arrList = CreateObject("System.Collections.ArrayList")


2.添加或插入item
2.1 添加item
  Add方法,语法:arrList.Add item
示例:
arrList.Add "美好的一天"
arrList.Add "52"
arrList.Add 5

说明:
item 可以是数字,字符串,对象等变量。文本必须加"",数字可加可不加(会影响其他操作,具体在相关条目中说明)。
item 可以重复。

2.2 插入item
  Insert方法,在指定索引位置插入item
  语法:arrList.Insert 索引号,数据
示例:
arrList.Insert 0, 10    '在最前面插入10,索引从0开始


3.查找或删除item
3.1 查找(判断item是否存在)
Contains属性,真表示存在,假表示不存在
语法:ArrayList.Contains(item) [= true/false]
说明:可用此法去重。

3.2 删除
3.2.1 按item删除
语法:ArrayList.Remove item
示例:
arrList.Remove "15"  '删除item是15的内容
说明:按添加顺序删除(先添加先删除)。特别要注意的是:对于数字,添加时有没有加"",删除时也要一样,否则不会报错,但也不会删除。

3.2.2 按索引删除
语法:ArrayList.removeat 索引号
示例:
arrList.removeat 1  '删除索引号为1的item,索引从0开始

3.2.3 全部删除
语法:ArrayList.Clear
说明:清空所有item,以备再次使用。再次使用时,无需重新绑定。


4.排序
4.1 升序排序
语法:ArrayList.sort

4.2 降序排序
语法(下面两句联合就是降序排列):
ArrayList.sort
ArrayList.Reverse

说明:
当item是数字时,若add时没加"",排序时按数字大小排序。例如升序排序:1,2,5,12,26,35。若add时加了"",默认为文本,升序排序就变成了:1,12,2,26,35,5。


5.复制
使用Clone方法可以创建ArrayList的全新副本。
语法:Set arrList2 = arrList.Clone
说明:此法"克隆"的副本arrList2 与原arrList 相互独立,可单独操作,互不干扰。
注意:如果使用语句:Set arrList2 = arrList,将指向同一个ArrayList。


6.输出(可转数组)
6.1 循环提取item
语法:
    For i = 0 To arrList.Count - 1     'arrList.Count表示集合中item的数量
        Debug.Print arrList(i)     '表示方法和一维数组一样,i为索引号,从0开始
    Next i
或者:
    For Each k In arrList
        Debug.Print k
    Next k

6.2 输出到一维数组
ToArray方法
语法:arr = arrList.toarray   '索引号从0开始的一维数组


7.释放(删除)arrList
语法:Set arrList = Nothing
说明:再次使用时,需要重新绑定。

-------------------------
实例:将所有得分按序排成1列(或者去重后排序)

得分1        得分2        得分3        得分4        得分5
  72             68             87             89             86
  67             78             86             75             67
  89             97             68             79             97
  81             54             78             42             94
  71             45             85             44             75

代码示例:
Sub test()
    Dim arrList As Object, k
    Set arrList = CreateObject("System.Collections.ArrayList")   '后期绑定
    arr = Range("A2:E" & Cells(Rows.Count, 1).End(3).Row).Value
    For Each k In arr
        arrList.Add k   '添加item。若要去重,用下句代替本句即可
        'If Not arrList.Contains(k) Then arrList.Add k   '判断item不存在时添加
    Next k

    arrList.Sort
    arrList.Reverse '降序

    brr = arrList.toarray   '输出到数组brr
    Range("h2").Resize(UBound(brr) + 1, 1) = Application.Transpose(brr) '返回单元格
    Set arrList = Nothing   '释放arrList
End Sub

补充:谢谢魂断蓝桥的提醒:在文本数值混合时排序报错。需要排序时,请全部使用文本或数值。

参考链接:
https://cloud.tencent.com/developer/article/1485933
https://blog.csdn.net/lyfegf/article/details/103746134
https://blog.csdn.net/lyfegf/article/details/103750912

评分

23

查看全部评分

TA的精华主题

TA的得分主题

发表于 2020-8-21 09:21 | 显示全部楼层
可以,如果文本数值混合的情况下,排序出错

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-8-21 10:08 | 显示全部楼层
本帖最后由 lmgz007 于 2020-8-21 10:12 编辑
魂断蓝桥 发表于 2020-8-21 09:21
可以,如果文本数值混合的情况下,排序出错

是的,谢谢提醒。发布时疏忽了。

TA的精华主题

TA的得分主题

发表于 2020-8-21 15:08 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
'混合排序也是可以变通一下的。。。Sub test()
Dim ar, i
Dim list: Set list = CreateObject("system.collections.arraylist")
ar = Array("1", 7, "8", "A", 3, "b", 5, "你好")
For i = 0 To UBound(ar)
   list.Add CStr(ar(i))                             '用Cstr转换成文本
Next
list.Sort
For i = 0 To list.Count - 1
    Debug.Print list(i)
Next
End Sub

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'顺便补充两个你没提到的方法,Getrange 和Setrange,类似于其他语言里的数组切片操作。
Getrange:
类似于VBA的mid函数,只不过mid是对字符串,而Getrange是对动态数组。
Setrange:
类似于VBA的Replace,同样replace是对字符串,而Setrange是对动态数组。
下面是个示例,只是为了说明两个方法的使用,其他无意义。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Sub list切片()                        '元素交换位置a,b,c,d 变成c,d,a,b
Dim Mylst As Object, mylst2 As Object, x As Object, y As Object, i
Set Mylst = CreateObject("System.Collections.Arraylist")
Mylst.Add "a":  Mylst.Add "b":  Mylst.Add "c":  Mylst.Add "d"
Set mylst2 = Mylst.Clone        '克隆一个list

Set x = Mylst.GetRange(2, 2)    '切片操作,获取mylst后两个数(一参为起始位置,二参为个数,类似于Mid的写法)
Set y = mylst2.GetRange(0, 2)   '获取mylst2的前两个数

Mylst.SetRange 0, x             '替换a,b 为 c,d
Mylst.SetRange 2, y             '同样可以用截取的mylst2的片段来替换。替换c,d 为 a,b

For i = 0 To Mylst.Count - 1    '替换后,abcd就变成了cdab
    Debug.Print Mylst(i)
Next

End Sub

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
最后,多说一句,这个对象的使用,要注意的细节挺多,同在VBA下嵌入不同的结构(比如递归,貌似不能保存每层的状态)时使用不太一样。还有就是从VBA数组转换成Arraylist时,有时你会发现加不进去,这时就要转换了。。。,不过就像你说的用的人少,很少人会关注这些的,但用来做简单的排序还是挺方便的。

评分

8

查看全部评分

TA的精华主题

TA的得分主题

发表于 2020-8-21 16:03 | 显示全部楼层
不过我发现速度远远比不上字典啊。。。不重复写入10万条, 大概要十几秒。
字典1秒。

TA的精华主题

TA的得分主题

发表于 2020-8-21 18:41 | 显示全部楼层
各取所需,取长补短,标记一下,谢谢分享!

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-8-21 19:25 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
astupig 发表于 2020-8-21 16:03
不过我发现速度远远比不上字典啊。。。不重复写入10万条, 大概要十几秒。
字典1秒。

是的,它的优点和缺点都很明显,如果不去重,10万数据排序也就零点几秒。我认为作为入门级的应用足够了,不要去钻研高深的排序算法,比一般的排序要快。对于大量数据的复杂处理还是首选字典。

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-8-21 19:28 | 显示全部楼层
wodewan 发表于 2020-8-21 15:08
'混合排序也是可以变通一下的。。。Sub test()
Dim ar, i
Dim list: Set list = CreateObject("system.co ...

谢谢你的补充,我本来就是起个抛砖引玉的作用。希望得到各位的充实,集思广益。

TA的精华主题

TA的得分主题

发表于 2020-8-21 19:56 | 显示全部楼层
貌似类似c#中的数组用法

TA的精华主题

TA的得分主题

发表于 2020-8-21 20:24 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
技术贴,学习了,留个记号,
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-16 09:28 , Processed in 0.050155 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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