一、问题导入
问题描述:文件“DEMO-2-使用数组大幅度提升VBA代码执行效率”中有20万条记录,需要根据区域求汇总金额,用for循环处理(注意i不能定义为integer,溢出),耗时较长。
处理过程:(1)希望准确记录耗时,引入timer函数(返回从午夜到现在经过的秒数),运行前 t=timer,运行后“MsgBox Timer - t”
(2)耗时较长的原因在于:每次循环都要到单元格“n5”中取值,若每次是取变量值,则速度大幅提高,因此dim str as string,str=range("n5")后,替换循环中的“n5”
(3)将for循环中的单元格取数替换成变量取数,能大幅提升速度,能否将其中每次循环的到Range("g"&i)取数替换成变量?
(4)i从2到200000,Range("g"&i)是一系列数字在一起,因此是数组,引入数组概念。定义数组:Dim arr()给数组赋值:arr=range("a1:d7"),如何取数?
(5)用一小段区域演示数组取值arr(x,y),其中x是数组区域的行数,y是数组区域的列数;
(6)用数组替换原代码,大幅提升速度。
二、进一步认识数组
“”认识数组“文件”:(1)数组分一维、二维、多维,上例是二维数组;
(2)一维数组定义时应指定标号范围,如Dim arr(1 to 5),否则容易报错;
(3)可一个一个地将一维数组的值赋给变量,如i = arr(2),也可一次赋给区域,如Range("a1:e1")=arr;
(4)一维数组默认是行方向数组,因此只能给行区域一次性赋值,若给列区域赋值,如Range("a1:a5")=arr,结果是列区域获得的值都是arr(1);
(5)若用区域给数组初始化,则无论区域如何,生成的是二维数组,如arr=Range("a1:a5"),虽仅一列,但赋值时需用二维方式:Range("c1")=arr(2,1)
(6)回顾split函数截取字符,生成的结果是数组,进一步理解该函数的应用。
三、进一步认识数组(查找销量冠军)
问题描述:要完成表中“销售额最高的产品“和”该产品的销售额”,传统做法需新建辅助列进行计算后查询填入,较麻烦,有时甚至不方便操作辅助列。
处理过程:(1)引入数组,规避辅助列问题,如下左边代码;
(2)用Application.WorksheetFunction.Max(arr)查询到最大的销售额,填入;
(3)需找到其对应产品名称,先找其在数组中位置为:Application.WorksheetFunction.Match(Range("h3"), arr, 0) + 1,因此可得产品名称为
Range("a" &Application.WorksheetFunction.Match(Range("h3"), arr, 0) + 1)
tips:Match(要在表中查找的值, 可能包含所要查找的值的连续单元格区域, 0),其中0代表等于匹配,返回相应位置
(4)上述解决过程的缺陷在于需事先确定数组大小,但往往不易确定。改进:先定义为不定arr(),再redim。(不允许直接以变量dim arr(1 to j))
(5)了解两个函数:UBound(arr),LBound(arr),分别返回数组标号的上下限,用其可方便构造数组的循环。
Dim arr(1 to 5) For i = 1 To 5 arr(i) = Range("b" & i + 1) * Range("c" & i + 1) Next |
Dim arr() Dim j, i As Integer j = Range("a65536").End(xlUp).Row - 1 ReDim arr(1 To j) |
四、排列组合计算回款信息
凑数,用四层循环,太慢。
改用数组: Dim arr() arr=range("a1:a80") 容易测算运行时间减少倍数。
注意新的跳出循环方式:GoTo 语句
用法: 循环内找到时:GoTo 100,然后在跳出的地方写:“100 (换行)继续执行的语句”