本帖最后由 佛山小老鼠 于 2012-11-8 10:54 编辑
第十三讲 VBA数组基础(一) 一. 什么是数组? VBA数组就是储存一组数据的数据空间,它是由连续可索引的且具有相同的数据类型成员集合。数组中的每一个成员都具有唯一的索引号,数组存在于内存中,平常我们是把数据存在于工作表中的单元格里。 二. 数组的特点 1. 读写速度快 学VBA的朋友,刚开始时,不会怎么要求关注运行速度,但是当你处理大量数据时,当你的VBA水平不断提高时,可能你就有这方面的意识了,Vba读取内存中的数据远远比从读取对象中的数据要快,有了这个特点,往往VBA爱好者一有机会就会用数组处理数据。 (1).实例 对比下面两段代码的运行速度
- Sub test1() '用时0.12秒
- Dim t As Single, i As Integer, s As Long, arr As Variant
- t = Timer
- arr = Range("A1:A1000000")
- For i = 1 To 5000
- s = s + arr(i, 1) '直接调用内存中的值
- Next i
- MsgBox Format(Timer - t, "0.00秒")
- End Sub
复制代码
- Sub Test2() '用时7.32秒
- Dim t As Single, i As Long, s As Long
- t = Timer
- For i = 1 To 1000000
- s = s + Cells(i, 1) '调用单元格中的值
- Next i
- MsgBox Format(Timer - t, "0.00秒")
- End Sub
复制代码
从上面两段代码大家可以看出,第一段代码用了数组,第二段代码是从单元格中读取数据,速度差那么远,第一段代码没有感觉到等,第二段感觉在等待。所以大家说说,要不要学数组。因为数组的运行速度快。
2. 无法永久保存 数据存放在工作表中单元格里可以永久保存,但存放在数组中数据只你要关闭Excel程序,不管是你是模块级变量,还是全局性变量,都会消失,以前的任何数组都不存在了。 三. 数组的分类 1. 按维分 (1).一维数组 相当于工作表里单行,不能是单列,如果要转为单列,就要借助于工作函数里转置函数Transpose (2).二维数组 相当于工作表里单元格区域,是一个矩形区域,多行多列 (3).还有三维,四维,他们说可以到60维,我都不会,也不理解,在我们Excel里VBA几乎用不到三维,所以大家了解二维和一维就可以了。 2. 按其它的分 (1).常量数组 如array("a","b","c") (2).静态数组 我们定义变量时就知道数组的维数和数组的上下界 (3).动态数组 我们定义变量时不知道数组的维数和数组的上下界 四. 向数组中写于数据
- Sub test1() '写入一维数组
- Dim i As Integer
- Dim arr(1 To 100)
- arr(1) = "佛山"
- arr(2) = "老鼠"
- arr(3) = "佛山小老鼠"
- End Sub
复制代码
- Sub test2() '向二维数组写入数据,二维数组和我们工作表时的单元格区域相似,这样大家可能好理解一点
- '先循环行,然后再循环列
- Dim x As Integer, y As Integer
- Dim arr(1 To 7, 1 To 4)
- For x = 1 To 7
- For y = 1 To 4
- arr(x, y) = Cells(x, y)
- Next y
- Next x
- MsgBox arr(2, 2)
- End Sub
复制代码
- Sub tets3() '动态数组
- Dim arr(), MyRow As Integer, i As Integer '定义变量,定义Arr为动态数组,因为我们不能确定数组Arr的一维上标
- MyRow = Cells(Rows.Count, 1).End(xlUp).row '取得A列最后一个数据的单元格的行号
- ReDim arr(1 To MyRow, 1 To 4) '重新定义数组Arr ,大家记得,前面我们定义它Dim Arr(),现在还要给它定义一次,因为现在知道它的上标了
- '所以用了 ReDim arr(1 To MyRow, 1 To 4)
- For x = 1 To MyRow '遍历单元格区域,然后通过循环一一把单元格里的数据写于数组
- arr(x, 1) = Cells(x, 1) '第X行第1列
- arr(x, 2) = Cells(x, 2) '第X行第2列
- arr(x, 3) = Cells(x, 3) '第X行第3列
- arr(x, 4) = Cells(x, 4) '第X行第4列
- Next x
- End Sub
复制代码
- Sub test4() '由常量数组导入
- Dim arr
- arr = Array(1, "A", 3, "佛山小老鼠")
- End Sub
- Sub test5() '由单元格区域导入
- Dim arr '
- arr = Range("a1:d7") '大家注意,这种赋值,我们就不能指定数组的上下标,如果指定就会报错
- 所以直接用了Dim arr
- End Sub
复制代码
五. 动态数组的扩充
1. 用ReDim Preserve arr1(一维变量),这个是扩充一维的 2. 用ReDim Preserve arr1(一维,二维变量),这个只能扩充二维的 备注 大家务必要记得动态数组的扩充是扩展末维的,如二维的你就不能扩充一维,你只能扩充二维的变量 实例 把B列有小老鼠的记录筛选出来放在F1
- Sub test1()
- Dim arr, arr1() '定义arr为数组,arr1为动态数组
- Maxrow = Cells(Rows.Count, 2).End(xlUp).Row '最大B列最后一个有数据的行号
- arr = Range("A1:D" & Maxrow) '把单元格区域一次写于数组
- For i = 1 To Maxrow '遍历数组Arr中的行数据, 相当于遍历B中的数据
- If arr(i, 2) = "小老鼠" Then '如果数据是“小老鼠“那么
- k = k + 1 '累加K值
- ReDim Preserve arr1(1 To 4, 1 To k) '重新定义数组Arr1,且要保留原有的数据,二维的下标你从1开始,那么刚好和数组 arr一致,这个地方一定要注意
- '为什么二维不直接写个k,而写成1 to k,还有一个原因,Resize(k, 4)吻合。直接用K就见Test2的的写法
- arr1(1, k) = arr(i, 1) '把数组Arr中符合条件重新放到新数组arr1中
- arr1(2, k) = arr(i, 2) ' 大家可以这样理解它,数组arr的列就是数组arr1中的行
- arr1(3, k) = arr(i, 3) '数组arr的行就是数组arr1中的列,为什么要这样呢?是因为
- arr1(4, k) = arr(i, 4) '给二维数组重新定义数组时扩充只能扩充二维,不能扩充一维,最后通过转置函数又转回来
- End If
- Next i
- [F1].Resize(k, 4) = Application.WorksheetFunction.Transpose(arr1) '又通过转置函数又转回来
- End Sub
复制代码
- Sub 清空()
- Range("F:I").Clear
- End Sub
复制代码
- Sub test2()
- Dim arr, arr1() '定义arr为数组,arr1为动态数组
- Maxrow = Cells(Rows.Count, 2).End(xlUp).Row '最大B列最后一个有数据的行号
- arr = Range("A1:D" & Maxrow) '把单元格区域一次写于数组
- For i = 1 To Maxrow '遍历数组Arr中的行数据, 相当于遍历B中的数据
- If arr(i, 2) = "小老鼠" Then '如果数据是"小老鼠"那么
- ReDim Preserve arr1(1 To 4, k) '重新定义数组Arr1,且要保留原有的数据,二维的下标从0开始
- arr1(1, k) = arr(i, 1) '把数组Arr中符合条件重新放到新数组arr1中
- arr1(2, k) = arr(i, 2) ' 大家可以这样理解它,数组arr的列就是数组arr1中的行
- arr1(3, k) = arr(i, 3) '数组arr的行就是数组arr1中的列,为什么要这样呢?是因为
- arr1(4, k) = arr(i, 4) '给二维数组重新定义数组时扩充只能扩充二维,不能扩充一维,最后通过转置函数又转回来
- k = k + 1 '累加K值
- End If
- Next i
- [F1].Resize(k, 4) = Application.WorksheetFunction.Transpose(arr1) '能通过转置函数又转回来
- End Sub
复制代码
'大家要注意,如果二维的下标从1开始,那么累加计数K=K+1就要写在重新定义数组的前面,
'如果二维的下标从0开始,也就是直接写个K ,那么累加计数K=K+1就要写在重新定义数组的最后面了,不然会报错,下标越界. 3. 另一种途径来动态数据的扩充,就比上面的方法简单了许多,也就是我首先申请足够大的空间 Dim arr1(1 To 100000, 1 To 3) 实例 把B列有小老鼠的记录筛选出来放在F1
- Sub test3()
- Dim arr1, arr2(1 To 300000, 1 To 4) '定义一个足够大的数组空间
- Maxrow = Cells(Rows.Count, 2).End(xlUp).Row '最大B列最后一个有数据的行号
- arr1 = Range("A1:D" & Maxrow) '把区域赋值给数据arr1
- For i = 1 To Maxrow '遍历所有数组一维
- If arr1(i, 2) = "小老鼠" Then '如果数组成员有等于“老鼠”的。那么
- k = k + 1 '累加k记数
- arr2(k, 1) = arr1(i, 1) '满足条件,就把arr1成员写到新数组arr2里
- arr2(k, 2) = arr1(i, 2)
- arr2(k, 3) = arr1(i, 3)
- arr2(k, 4) = arr1(i, 4)
- End If
- Next i
- [F1].Resize(Maxrow, 4) = arr2 '把新数组一次性写于单元格
- End Sub
复制代码
六. 数组的上下标
1. Lbound(数组) 可以获取数组的最小下标 2. Ubound(数组) 可以获取数组的最大上标 3. Ubound(数组,1) 可以获得数组(第1维)最大上标 4. Ubound(数组,2) 可以获得数组的(第2维)的最大上标 七. 清空数组 Erase 1. 表达式 Erase 数组名 2. 实例 把A列的数据以空格为断点,依次放到E,F,G列
- Sub test1()
- Dim i As Long, MaxRow As Long, arr1, arr2() '定义相关的变量
- MaxRow = Cells(Rows.Count, 1).End(xlUp).Row + 1 '取得A列最后一个有数据的单元格的下一个单元格
- ' 为什么还要加上1呢?,因为只有找到下一个空格,才会把空格上面的数据读出来
- arr1 = Range("A1:A" & MaxRow) '把单元格区域写于数组
- For i = 1 To MaxRow '遍历数组一维
- If arr1(i, 1) = "" Then '如果数组成员为空,那么
- k = k + 1 '累加k,目的是它们分别显在在E,F,G列
- Cells(1, 4 + k).Resize(UBound(arr2), 1) = Application.WorksheetFunction.Transpose(arr2)
- '把数组arr2一次性写于单元格区域
- Erase arr2 '然后清空数组arr2空间,目的是为了存放另一空格下面的数据
- x = 0 '重新初始化x,因为下一个空格下面的数据不一样,所以要归0,不然的话前面就会有空单元格出现
- Else
- x = x + 1 '累加x
- ReDim Preserve arr2(1 To x) '重新定义动态数组Arr2
- arr2(x) = arr1(i, 1) '把数组arr1满足条件的成员赋值给数组arr2
- End If
- Next i
- End Sub
- Sub test2()
- Range("E:G").Clear
- End Sub
复制代码
|