ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[原创] 通过一维数组的方式访问/修改其他数组的数据

[复制链接]

TA的精华主题

TA的得分主题

发表于 2024-11-5 15:34 | 显示全部楼层 |阅读模式
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 leolee82 于 2024-11-5 16:28 编辑

参照C++中的StringView,写了一个clsArrayView1D。可以在不复制数组数据的前提下,通过一维数组的方式访问/修改其他数组的数据,可以在某些情况下提高程序运行速度。应用场景:
1. 通过一维数组的方式访问二维数组的列
2. 一维数组的子数组
3. 通过SafeArrayCopyData 将一维数组赋值给二维数组的某列/一维数组的子数组

实际上一个成员函数就可以搞定,拆成几个成员函数的目的是,在循环中可以避免重复执行一些代码。如有未考虑到的地方,欢迎大家指正。
clsArrayView2D的代码类似,就不放上来了


使用场景示例如下:

  1. Private Declare Function SafeArrayCopyData Lib "oleaut32.dll" (ByVal psaSource As Long, ByVal psaTarget As Long) As Long

  2. Sub TestclsArrayView1D()
  3. Dim arrView1, arrView2, o1 As New clsArrayView1D, o2 As New clsArrayView1D
  4. Dim p1 As Long, p2 As Long

  5. '访问二维数组的列,二维数组数据是按列存储的
  6. arr1 = [a1:b3]
  7. With o1
  8. 'With CreateObject("EXDIY.clsArrayView1D")
  9.     .Initial arr1
  10.     .SetArrayViewVariant arrView1
  11.     p1 = .CreateArrayView(1, 2, 3, 0) '使用arrView访问arr的第二列
  12.    
  13.     arr3 = arrView '复制arr的第二列为一个一维数组

  14.     '以一维数组方式访问arr的第二列
  15.     Debug.Print arrView1(0), arrView1(1), arrView1(2) '4,5,6
  16.    
  17.     '修改arr第二列数据
  18.     arrView1(0) = "A"
  19.     arrView1(1) = "A"
  20.     arrView1(2) = "A"
  21.    
  22.     Debug.Print arr1(1, 2), arr1(2, 2), arr1(2, 2) 'A,A,A
  23. End With

  24. '一维数组子数组
  25. arr2 = Array(0, 1, 2, 3, 4)
  26. With o2
  27. 'With CreateObject("EXDIY.clsArrayView1D")
  28.     .Initial arr2
  29.     .SetArrayViewVariant arrView2
  30.     p2 = .CreateArrayView(2, 0, 3, 0) '使用arrView访问arr(2)和arr(3)
  31.    
  32.     Debug.Print arrView2(0), arrView2(1), arrView2(2) '2,3,4
  33.    
  34.     '复制arr1第二列数据到arr2,前提是ArrayView的数据类型相同,数组大小相同
  35.     SafeArrayCopyData p1, p2
  36.    
  37.     Debug.Print arr2(2), arr2(3), arr2(4)  'A,A,A
  38.    
  39.     arrView2(0) = "C"
  40.     arrView2(1) = "C"
  41.     arrView2(2) = "C"
  42.    
  43.     '将一维数组赋值给二维数组的某列
  44.     SafeArrayCopyData p2, p1
  45.     Debug.Print arr1(1, 2), arr1(2, 2), arr1(2, 2) 'C,C,C
  46. End With
  47. End Sub
复制代码

工作簿3421.rar (22.96 KB, 下载次数: 6)



TA的精华主题

TA的得分主题

发表于 2024-11-5 19:44 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
这个只能用在32位系统中。

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-11-6 08:38 | 显示全部楼层
ykcbf1100 发表于 2024-11-5 19:44
这个只能用在32位系统中。

只装了WPS,32位的OFFICE应该也没问题,平常也用不到大文件,习惯了。这些基础类和函数都是封装在VB6里,代码估计有3万行了,没精力升级到VB.NET。
64位的话需要改改API声明,指针相关的数据类型,并注意SAFEARRAY和VARIANT结构的变化

TA的精华主题

TA的得分主题

发表于 2024-11-6 09:45 | 显示全部楼层
用CopyMemory也可以吧,就是有时候会崩掉,不太稳定。
  1. Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)

  2. Sub test()
  3. Dim arr, brr(2)
  4. arr = [a1:b3]
  5. '取第2列的数据给brr数组
  6. CopyMemory brr(0), arr(1, 2), 3 * 24 '64位variant数组每个元素占24个字节,32位占16个字节
  7. Debug.Print brr(0), brr(1), brr(2)
  8. brr(0) = "x": brr(1) = "x": brr(2) = "x"
  9. CopyMemory arr(1, 2), brr(0), 3 * 24
  10. Debug.Print arr(1, 2), arr(2, 2), arr(3, 2)
  11. End Sub
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-11-6 10:09 | 显示全部楼层
大灰狼1976 发表于 2024-11-6 09:45
用CopyMemory也可以吧,就是有时候会崩掉,不太稳定。

数值类型或数值类型Variant的可以用CopyMemory,数组元素是字符串、自定义、数组之类需要另外分配内存的就不行了,就会造成两个变量指向同一份内存数据,源数组变量先释放内存就会有问题了。这就是CopyMemory不稳定的原因。对于简单数据类型SafeArrayCopyData内部应该也是这样实现的,可参考
http://www.yfvb.com/help/cwin/in ... ng_a_safe_array.htm

通过数组描述符创建个假数组访问数据,用完后类的析构函数会自动解除对数据的引用,就比较安全了
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-11-21 22:22 , Processed in 0.029839 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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