access vba 常量数组赋值_聊聊 VBA 数组的那些坑

de3e542bcfec91f4e2392c51fff0c557.png

为什么使用数组?

1. 缩减工作薄文件大小,提高运行效率

一般而言只是使用 Excel 的内置工作表函数,在运算方面还是很高效的,但有时因为一个单元格牵扯的计算太多,比如调用多单元格数据,对结果文本进行部分替换,按照优先级和条件判断来确定不同的返回结果,这都会造成一个单元格的公式文本过长,当以此单元格为基础进行数千行的相对引用填充时,必然会导入工作薄快速的膨胀;

如果因为某些复杂的处理,而使用了自定义函数,且应用的单元格也是几千行级别的,那么用户甚至会被迫选择在 "公式选项卡->计算选项",将自动计算变更为手动计算的方式来避免这种 Excel 自动进行全局计算的引发卡顿问题;

使用数组避免这一问题的方式就是将计算在内存完成,单元格只写入一个数值或字符串;

2. 数组的运算效率远高于读写单元格

看个实例来体会一下单元格逐个处理,和数组内存处理后统一导入的效率差异;

插入代码块的高亮显示实在不理想,先贴图吧;

d06da48175aded264d5231efa70d94d6.png

FillRandom 在 A1:D10000 这四万个单元格中生成随机数;拷贝随机数为常数,避免触发自动计算带来的开销;

任务目标:对每个随机数求平方,结果放置回工作表;

ForEachCellImplement 使用逐个单元格取值,计算后放回的方式实现;

ArrayImplement 使用将 A1:D10000 导入数组,在内存中完成计算,再统一放回工作表的方式实现;

前者耗时 12718 毫秒,后者 47 毫秒;约 270 倍的效率差异;

3. 在某些应用场景下,数组处理问题最简单

把一行或一列单元格的数据以逗号拼接成字符串,在不使用数组的情况下一般会这样做;

即便省略 resStr,If 语句整体压缩在一行,也需要 5 行代码,其中包含循环结构和条件判断处理字符串拼接的开头部分 ;

如果使用数组,只需要一行就可以了;

99e6463bf041bc6fc1c25239ed6e094f.png

4. 强化部分 Excel 功能

如,SpecialCells,也就是 Excel 快捷键 F5 定位条件,Excel 中可以批量定位一种类型的单元格区域,但对定位结果进行多种条件处理,再将数据放回或者以这些数据为基础再进行其他数据的生成,Excel 菜单功能是无法完成的;

Find 也就是 Excel 的 Ctrl + F,查找功能,同样可以利用 VBA 来完成,一旦拿到返回的一组单元格区域,处理方式就灵活多样了;

整体来看数组可以极大的拓展 “返回值为单元格区域” 的功能的操作边界;

5. VBA 其他容器使用效果也不理想

比如 Collection(类似 Python 中的 List),Dictionary等,但支持的方法太有限,同时转换类型也没有便捷的方法来支持;

这一点我个人理解是 Microsoft 还是希望用户以 Range 为核心,配合 Excel 本身的功能,以及这些功能对应的 VBA 调用,以此来完成任务目标; 如果用户的任务目标超越了这个界限用户就应该去使用 Microsoft 的其他产品如 Power BI,VSTO(Visual Studio Tools for Office)借助 C# 应该是想干什么都可以了;或者干脆极易上手 Python,借助 pandas 和 numpy 这些工具来处理 .xlsx .csv 等等;

坑的原因

VBA 数组的坑主要是由三个原因引起的:

1.脚本语言的用户对数据类型的重视度不足;

2.Range对象的存在,造成了数组一些潜规则式的转换机制;可以在下文 “感受 Range 的混乱” 部分体会一下;

3.静态数组和动态数组的一些限制和数据导入规则;这远没有静态语言数组声明后全生命周期大小不可变,扩容需要重新创建来的清晰;

感受 Range 的混乱

如果这部分看蒙了就暂时过的它吧,后面看过 “Array() 和 Range 对象”,“数组初始化方式3”,“数组导入到单元格区域”,在回过头来理解一下这个部分会更有收获;

1.Range("") 赋值给未声明的变量,TypeName 变为 Variant;TypeName() 是获取变量的数据类型;

2.Variant() 不能使用 Range 类型的属性,如,.Address;

3.想要使用 Range 类型的属性,先 Set varName = Range("");

4.对于被 Set 成 Range 类型的变量:

(1)IsArray() 仍然是 True;

(2)不能将 Range 类型的变量赋值给已经声明的数组,报错 “类型不匹配”;

(3)可以赋值给未声明的变量或 Variant 类型的变量(Dim x 或 Dim x as Variant),该 Range 类型的变量会自动转型为 Variant();

最让人懵逼的地方是 Set 一个 Range() 它的 TypeName 是 Range,IsArray 是 True,但不能把它赋值给一个数组,如果把它赋值给一个 未声明的 或 Variant 变量,它又被自动转换成了 Variant(),看下面这个例子,注意 TypeName:

c43f10a410ec502c4eb58564f89750d8.png

以下主要从以下几个方面来谈谈数组避坑:

  1. 数组声明
  2. Array() 方法 和 Range 对象
  3. 数组初始化
  4. 数组导入到单元格区域
  5. 数组作为参数和返回值

对于脚本语言我个人更倾向,不开启强制变量声明;

在不声明的状态下,直接对一个变量赋值,某些时候是更好的策略,比如,Filter() 的返回值,如果声明了 Variant() 去接收则报错(必须声明为 String()),For Each 的临时变量,会强制用户声明等等;如果要开启强制声明,在模块最上方加入如下语句:

Option Explicit

数组声明

静态数组

在 Option Base 的指定值不同的情况下,不设置编号的静态数组声明的大小是不同的;

08a34a844cef9e4ec2da805f0afe60b9.png

动态数组

29e99d40d1125ba6b8f8a80c7b457e10.png

Array() 和 Range 对象

讨论初始化之前,先来看两个给数组赋值的常用形式;

所谓一次性装入,就是以一个数组或对象为数组赋值,赋值在一条语句中完成,Array() 和 Range 对象都属于一次装入;

非一次性装入,就是利用循环结构逐个调用数组元素并进行赋值;

1. Array() 函数

Array(ParamArray ArgList() As Variant)

注意 Array() 方法的参数和数据类型是 Variant,其函数的返回值是 Variant();

aa3e8df931cf7191bad9edf031b064a7.png
官方文档 Variant 数据类型​docs.microsoft.com

Variant 包含除固定长度 String 数据以外的任何类型的数据;也就是说 Array() 的元素可以是任意类型,也可以是数组;

2. Range 对象

先说明一下本文用到的几个称呼,它们都是 Range对象 :

(1)单元格区域,特指工作表中由单元格(Cell)所组成的 Range;

(2)Range 类型,将 Range("A1:C3") 这种形式通过 Set 设置后得到的对象变量;

(3)Range(""),特指赋值给变量,数据类型转型为 Variant() 的 Range;

(4)Range 对象,指代 (1)-(3)中的情况,需要结合上下文来理解;

ae192a829a5219ef3d09dab21a37926b.png

数组初始化

几条规则:

1.静态数组不能一次性装入数据;

2.只声明是数组、大小及编号的数组,系统会分配为 Variant类型数组;

3.只声明一个变量 (如,Dim varTemp),默认的数据类型 TypeName(varTemp) 是 Empty,varTemp 可以接收动态或静态数组,且可以是任意类型的数组;这种声明方式实际上就相当于在 非 Option Explicit 情况下,不声明直接使用变量;

4.可以给 Variant数组 的元素赋值任意类型(逐个赋值的方式),但不能将 非Variant数组,赋值给 Variant数组(一次装入的模式),实际这一条是特指动态数组的,因为静态数组已经被不能一次装入的规则限制了;

5.可以用静态数组为动态数组赋值,但静态数组只能是 Variant数组;

d83dbed298ffe58e42e2b3ec94b0eeff.png

在 VBE 本地窗格对比一下数组元素的顺序 和 For Each 取元素的顺序;

b089ac8bce2cc9b7a655e58fd4322b5a.png

698327e7cdf61f44261106fd07996fa5.png

推荐使用不声明的方式,因为部分函数,如 Filter() 的返回值是 String(),Variant 数组使用元素逐个赋值的方式可以接收 String 类型的数据,但 Variant数组 不能接收 String数组 的一次性赋值,如果一定要为数组声明类型则需要声明为 Dim arrDyn() as String,这点个人觉得挺坑的;

46804a4383c4cae5569356cc590ae9fe.png

数组清理

这个用的不多顺便提一下吧;

Erase arraylist

arraylist 是一个或多个用逗号分隔开的需要清除的数组变量;只给出数组名,不带括号和下标;

Erase 释放动态数组所使用的内存,下次引用该动态数组之前,必须 ReDim

91d1277b5ee66433220203d385c879ad.png

数组导入到单元格区域

数组导入到单元格区域:

如果 数组 的大小超过了单元格区域的大小,则相当于数组被单元格区域截取,如,例1;

如果 单元格区域 的大小超过了数组的大小,则不足的部分以 "#N/A" 来填充,如,例2;

e6a17490ddad40486300ac9c6a51393c.png

例2,数组的大小是 3行4列,单元格区域的大小是 4行5列,不足的部分被 #N/A填充了;

6f3e50f0e48df5d4317fcfde433a84ac.png

821c08c4a6f86fc2cd68ea66c9558d53.png

虽然在数组初始化 方式3 中,提到 Range("") 赋值给数组,即便只有一行,它也是二维数组,但是将数组赋值给单元格区域时,可以使用一维数组;

4a68287031b95a6ee85cae5872387c3c.png

数组的转置

4b7337ded8b04fd98714d5c3bf8c0000.png

前面提到从 Range("") 导入的数组,即是是一行,也是二维数组,即 Range("A1:J1") 是 (1 to 1, 1 to 10) 的二维数组;

(1 to 1, 1 to 10) 形式的数组,也可以通过 Transpose 转置为一列数组,因此可以利用这个机制将一个 (1 to 1, 1 to 10) 转变为一个 (1 to 10) 的数组;

e932d2007243dab1150684fe6dee460e.png

这也就文章开头部分的两次转置的原理;在 VBE 本地窗口看一下结构

d9522c6a64fc1b025848bc54dabcd7fb.png

数组作为参数和返回值

edd9d408af028f2d9bd3bd289460a947.png

结束

数组日常使用能看到的出现概率较高的坑应该是都在这里了,以后想到其他的再补充吧,欢迎交流!

最后在补充一句,在文章开头的部分测试了四万个单元格的逐个读取和逐个写入,后来我又单独跑了一下逐个读取,时间是16毫秒左右,所以可以确定消耗资源的是单元格写入,在操作中尽量避免对单元格的写入吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/428281.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML文件可通过www进行传输,使用 zssh 进行 Zmodem 文件传输

Zmodem 最早是设计用来在串行连接(uart、rs232、rs485)上进行数据传输的,比如,在 minicom 下,我们就可以方便的用 Zmodem (说 sz 、rz 可能大家更熟悉)传输文件。只不过串口本身传输速度不快,文件大的话会让人有点崩溃。没有彻底把…

Linux下使用popen()执行shell命令

转载于&#xff1a;https://www.cnblogs.com/caosiyang/archive/2012/06/25/2560976.html 简单说一下popen()函数 函数定义 #include <stdio.h>FILE * popen(const char *command , const char *type ); int pclose(FILE *stream); 函数说明 popen()函数通过创建一个管道…

centos7安装python3.7.4_Centos7升级Python3.7.4

和大家技术分享一下当我们安装完成Centos7后&#xff0c;默认系统Python的版本为2.7.5。我们希望将Python升级到最新版本。 1、安装依赖项 yum install -y openssl-devel openssl-static zlib-devel lzma tk-devel xz-devel bzip2-devel ncurses-devel gdbm-devel readline-dev…

MyEclipse移动开发教程:迁移HTML5移动项目到PhoneGap(二)

MyEclipse开年钜惠 在线购买低至75折&#xff01;立即开抢>> 【MyEclipse最新版下载】 二、将文件从HTML5项目复制到PhoneGap项目中 1. 在HTML5 app项目的www/文件夹的资源中&#xff0c;单击右键&#xff0c;然后选择Copy。 从HTML5项目复制www资源2. 将资源粘贴到新Pho…

pb graph鼠标移上显示数据_Plotly数据可视化:离线版、微软vscode版的Python的基本作图...

1 介绍&#xff1a;1.1 Plotly 是一款用来做数据分析和可视化的在线平台&#xff0c;功能非常强大。1.2 Plotly是一个非常著名且强大的开源数据可视化框架&#xff0c;它通过构建基于浏览器显示的web形式的可交互图表来展示信息。1.3 具有多种语言python、javascript、matlab、…

centos安装无线网卡驱动_CentOS下显卡驱动安装的相关思考

背景&#xff1a;最近在安装显卡驱动&#xff0c;查找了一些网上的教程&#xff0c;但总感觉思路不够清晰&#xff0c;没办法弄清背后涉及的Linux原理&#xff0c;于是参考网上教程&#xff0c;并查阅了相关资料&#xff0c;希望能对显卡驱动安装作一个梳理&#xff0c;以做记录…

获取select被选中的option的值

<select id"select"> <option>绥江</option> <option>西江</option> <option>北江</option> <option>贺江</option> <option>新兴江</option> </select> $(funct…

红石32位cpu通用计算机,我的世界无命令方块32位红石电脑装置详解

来源&#xff1a;游戏园日期&#xff1a;2019-05-14 04:03:07我的世界无命令方块32位红石电脑装置详解。那下面给大家分享的是我的世界中的一个叫做机器编号为RSC-3230的红石电脑装置哦~有喜欢的顽疾啊不妨进来看看下的这个电脑哦~喜欢的话还可以下载下面的存档哦~本作品是一台…

python字符串字面量有哪四种定义方式_Python学习笔记(四)字符串型

字符串是 Python 中最常用的数据类型。我们可以使用引号(或")来创建字符串。 在最新的Python 3版本中&#xff0c;字符串是以Unicode编码的&#xff0c;也就是说&#xff0c;Python的字符串支持多语言。 创建字符串很简单&#xff0c;只要为变量分配一个值即可 View Code …

bzoj4380[POI2015]Myjnie dp

[POI2015]Myjnie Time Limit: 40 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 368 Solved: 185[Submit][Status][Discuss]Description 有n家洗车店从左往右排成一排&#xff0c;每家店都有一个正整数价格p[i]。有m个人要来消费&#xff0c;第i个人会驶过第a[i]个开始…

全国计算机等级考试用报名吗,全国计算机等级考试网上报名流程及考生报名使用说明...

全国计算机等级考试网上报名流程及考生报名使用说明附件&#xff1a;考生报名使用说明(一)注册账号和登录1)考生首次登录系统需要注册登录通行证&#xff0c;若考生有通行证账号&#xff0c;可以直接登录。2)考生也可使用其他账号登录&#xff0c;例如使用“QQ账号”登录。点击…

iptables nat实验_【零基础学云计算】LVS负载均衡群集之NAT模式搭建 (实践篇)...

实验原理图实验环境LVS调度器作为web服务器池的网关LVS服务器配置两块网卡分别连接内外网使用轮询&#xff08;rr&#xff09;调度算法LVS负载调度器网段规划 内网33网关&#xff1a;192.168.144.1 外网36&#xff1a;12.0.0.1web1 192.168.144.151web2 192.168.144.170nfs服务…

rs232串口驱动_RS232与RS485在性能上有啥区别和联系?老电工总结分析,一目了然...

串口是一种非常通用的设备接口&#xff0c;是仪器仪表设备常用的通信接口&#xff0c;常用于远程采集设备数据或者实现远程控制。串口的开发也比较简单&#xff0c;它是很多工程师最喜欢的接口之一。常见的串口协议有RS-232、RS-422、RS-485等&#xff0c;它是电子工程师面对的…

win7里面计算机叫什么,Win7电脑中的mrt.exe是甚么文件

咱们正在运用Win7体系的时分&#xff0c;只有咱们翻开使命办理便能够看失到有一个mrt.exe 步伐正在运转&#xff0c;也没有知叙mrt.exe 是甚么入程的&#xff0c;否不成以制止。这Win7电脑外的mrt.exe 是甚么文件呢&#xff1f;如今便随小编一同来看看电脑外的mrt.exe是甚么文件…

svn权限配置

转载于:https://www.cnblogs.com/wzlbigdata/p/8329601.html

pytorch gather_【Pytorch】Pytorch-1.1.0 版本新特性

2019年05月01日&#xff0c;Pytorch 1.1.0 版本正式发布啦~https://github.com/pytorch/pytorch/releases/tag/v1.1.0主要的几个功能&#xff1a;1. TensorBoard (currently experimental)2. JIT 的升级 [JIT] Attributes in ScriptModules [JIT] Dictionary and List Support …

MySQL-5.7.21非图形化下载、安装、连接问题记录

1、安装包下载链接&#xff1a;https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.21-winx64.zip 官网&#xff1a;https://www.mysql.com/downloads/ -> Community ->MySQl Community Sever ->选择与电脑对应的版本DownLoad 2、解压安装包到自定义的文件夹…

c++定义一个动态全局变量_静态链接与动态链接的宏观概述及微观详解

静态链接与动态链接的宏观概述及微观详解第一部分 宏观概述 1. 静态链接静态链接就是在程序运行前&#xff0c;链接器通过对象文件中包含的重定位表&#xff0c;完成所有重定位操作&#xff0c;并最终形成一个在运行时不需要再次进行依赖库的加载和重定位操作&#xff08;因为所…

pwm控制舵机转动角度程序_Mixly 第15课 舵机的使用

第15课 舵机的使用舵机的旋转不像普通电机那样只是转圈圈&#xff0c;它可以根据你的指令旋转到0至180度之间的任意角度然后精准的停下来。舵机的转动的角度是通过调节PWM(脉冲宽度调制)信号的占空比来实现的。舵机比较多的用于对角度有要求的场合&#xff0c;比如机器人、摄像…

1、初始JAVA

一、 语言的翻译分两种&#xff1a; 编译型语言&#xff1a;例如c语言、c语言 优点&#xff1a;速度快 缺点&#xff1a;不能跨平台 编译器编译——>特定平台的目标文件obj——>特定平台 解释型语言&#xff1a;例如PHP语言、JavaScript语言 优点&am…