为什么使用数组?
1. 缩减工作薄文件大小,提高运行效率
一般而言只是使用 Excel 的内置工作表函数,在运算方面还是很高效的,但有时因为一个单元格牵扯的计算太多,比如调用多单元格数据,对结果文本进行部分替换,按照优先级和条件判断来确定不同的返回结果,这都会造成一个单元格的公式文本过长,当以此单元格为基础进行数千行的相对引用填充时,必然会导入工作薄快速的膨胀;
如果因为某些复杂的处理,而使用了自定义函数,且应用的单元格也是几千行级别的,那么用户甚至会被迫选择在 "公式选项卡->计算选项",将自动计算变更为手动计算的方式来避免这种 Excel 自动进行全局计算的引发卡顿问题;
使用数组避免这一问题的方式就是将计算在内存完成,单元格只写入一个数值或字符串;
2. 数组的运算效率远高于读写单元格
看个实例来体会一下单元格逐个处理,和数组内存处理后统一导入的效率差异;
插入代码块的高亮显示实在不理想,先贴图吧;
FillRandom
在 A1:D10000 这四万个单元格中生成随机数;拷贝随机数为常数,避免触发自动计算带来的开销;
任务目标:对每个随机数求平方,结果放置回工作表;
ForEachCellImplement
使用逐个单元格取值,计算后放回的方式实现;
ArrayImplement
使用将 A1:D10000 导入数组,在内存中完成计算,再统一放回工作表的方式实现;
前者耗时 12718 毫秒,后者 47 毫秒;约 270 倍的效率差异;
3. 在某些应用场景下,数组处理问题最简单
把一行或一列单元格的数据以逗号拼接成字符串,在不使用数组的情况下一般会这样做;
即便省略 resStr,If 语句整体压缩在一行,也需要 5 行代码,其中包含循环结构和条件判断处理字符串拼接的开头部分 ;
如果使用数组,只需要一行就可以了;
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:
以下主要从以下几个方面来谈谈数组避坑:
-
数组声明
-
Array() 方法 和 Range 对象
-
数组初始化
-
数组导入到单元格区域
-
数组作为参数和返回值
对于脚本语言我个人更倾向,不开启强制变量声明;
在不声明的状态下,直接对一个变量赋值,某些时候是更好的策略,比如,Filter() 的返回值,如果声明了 Variant() 去接收则报错(必须声明为 String()),For Each 的临时变量,会强制用户声明等等;如果要开启强制声明,在模块最上方加入如下语句:
Option Explicit
在 Option Base 的指定值不同的情况下,不设置编号的静态数组声明的大小是不同的;
Array() 和 Range 对象
讨论初始化之前,先来看两个给数组赋值的常用形式;
所谓一次性装入,就是以一个数组或对象为数组赋值,赋值在一条语句中完成,Array() 和 Range 对象都属于一次装入;
非一次性装入,就是利用循环结构逐个调用数组元素并进行赋值;
1. Array() 函数
Array(ParamArray ArgList() As Variant)
注意 Array() 方法的参数和数据类型是 Variant,其函数的返回值是 Variant();
官方文档 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)中的情况,需要结合上下文来理解;
1.静态数组不能一次性装入数据;
2.只声明是数组、大小及编号的数组,系统会分配为 Variant类型数组;
3.只声明一个变量 (如,Dim varTemp),默认的数据类型 TypeName(varTemp) 是 Empty,varTemp 可以接收动态或静态数组,且可以是任意类型的数组;这种声明方式实际上就相当于在 非 Option Explicit 情况下,不声明直接使用变量;
4.可以给
Variant数组
的元素赋值任意类型(逐个赋值的方式),但不能将
非Variant数组
,赋值给 Variant数组(一次装入的模式),实际这一条是特指动态数组的,因为静态数组已经被不能一次装入的规则限制了;
5.可以用静态数组为动态数组赋值,但静态数组只能是 Variant数组;
静态
数组
是具有确定
大小
的
数组
。当你事先知道
数组
的
大小
时使用
静态
数组
。
静态
数组
的
大小
是在
数组
的声明语句里确定的,例如,语句DimFruits(10)As
String
声明了一个由10个成员组成的叫做Fruits的
静态
数组
。
动态
数组
是
大小
可以改变的
数组
。如果
数组
的
大小
每次都由程序运行而决定的话,就使用
动态
数组
。
Sub DynArray( )
Dim counter As Integer
'declare a dynamic array
Dim myArray( ) As Integer
'specify
今天和大家分享一个小的知识点,假如我们想知道我们Excel中间已经安装的所有字体,你是如何计算一共有多少字体的呢?你也许会打开开始选项卡,然后选择字体对话框,可是你殊不知这里面的字体有非常之多,我们不便把他们数出来,我们有没有简单的方法呢?答案是肯定有的。在这个时候我们用函数肯定是没有办法得到的啦!我们可以利用CommandBar来处理这个问题。此为官方的解释如下:我们还是先看看代码是如何实现的吧...
数组
是一个相当好的变量集合,里面可以存放许多按实际要求但是不可意料其值的值!
要使用
数组
,首先要定义
数组
,方能使用,如何定义,在上一篇已做了说明,在此不再阐述!
数组
根据不同的需求,可分为
静态
数组
和
动态
数组
,
静态
数组
存储欲先设置话的值,相当于里面存储一个或多个
静态
变量的值;
动态
数组
根据需要,可随时改变
数组
长度,并随时能修改存储的值;
本文提供几个简单的例子,以方便各位的学习!
抽象定义:
什么是
数组
:
数组
就是多个单位(element)有序的,连续存储在一起作为一个整体,统一叫1个名字(
数组
名)
如果已经是
数组
,那么arr1=arr1()
数组
名就代表
数组
数组
的序号叫 index,需要连续,但可以重复
数组
的内容叫 element,可以是各种内容
数组
函数定义的内容,arr1=array(1...
一、内建数据类型?
1、逻辑(logic)类型
SystemVerilog中有两种基本数据类型:变量和线网。各自有四种取值:0、1、x、z。RTL代码使用变量来存放组合和时序值,线网可以用来连接设计中的不同部分,例如门和模块实例。
syestemverilog对reg数据类型进行了改进,使得它除了作为一个变量外,还可以被连续
赋值
、门单元和模块驱动,这种数据类型被
数组
是有顺序的,通过索引来访问
数组
中的值。但是,
数组
中每个数据,类型必须相同。
VBA
中
数组
分为
静态
数组
和
动态
数组
。
静态
数组
:长度固定,ab都是数字,表示索引起始值。只写一个字时,默认从1开始,数字表示长度。
Dim
数组
名(a to b) As 数据类型
Dim MyArray1(10) As
String
Dim MyArray2(10 to 20) As Strin...
数组
在程序设计中,为了处理方便, 把具有相同类型的若干变量按有序的形式组织起来。这些按序排列的同类数据元素的集合称为
数组
。在C语言中,
数组
属于构造数据类型。一个
数组
可以分解为多个
数组
元...