VBA中数组(Array)与随机数(Rnd)的使用
作者: 奔跑的犀牛先生
本文链接:https://blog.****.net/xuemanqianshan/article/details/88962097
一 数组 array
1.1 数据定义
- 静态数组:长度不变的数组
- 动态数组:长度不定的数组,需要redim
- 数组 arr() 必须先声明后才可以使用!
1.2数组的index下标
- (1)数组的index下标应该是从0开始的,比如split生成的,还有未指定index下标的
- 如 dim arr1(5)
- (2)但是数组的index下标也有从1开始的情况,比如range 赋值的变量,默认下标从1开始
- 如 arr2=range("b1:d5")
- (3)数组的index下标受控制的情况
- 模块最前面 option base -1
- (4)数组index下标最好自己定义好
- 如 dim arr3(1 to 5)
1.3 数组严格定义的重要性
- Dim arr1(3)
- Dim arr1( 1 to 3)
- Option base 1 等等的意义
1.4 创建数组的方法
创建数组的方法
- (1) array()
- (2) split() (对应join)
- (3) 挨个元素赋值,甚至循环
- (4) 变量/对象 = range对象(值)
-
Sub test101()
-
rem 测试创建数组的各种方法
-
Dim arr1
-
Dim arr2
-
Dim arr3(0 To 3)
-
arr1 = Array(1, 2, 3, 4, 5, 6, 7)
-
arr2 = Split("a,b,c,d,e,f,g", ",")
-
arr3(0) = 1
-
arr3(1) = 2
-
Debug.Print arr1(1)
-
Debug.Print arr2(1)
-
Debug.Print arr3(1)
-
End Sub
二 数组必须声明大小后才可以使用
2.1 测试
- 变量可以不事先定义,也可以不赋初值
- 数组必须实现声明大小后才可以使用
- rem 变量可以赋初值,就可以表达式运算,不同类型的变量,默认初值不同
- rem 数组必须声明大小后才可以使用,包括运算,或者赋值
2.2 语法差别比较
- js 里 变量名 $a 字符串a
- 和其他语言不同的,其他语言标准 字符,字符串为 "", 变量名不用特殊标记
- 而js 标记了变量,本质是一样的
- python里 变量 a 字符串" a” 函数 func() 数组 list=[]
- 函数和数组形式完全不同,没有实现区分的必要性
- VBA里 变量 a 字符串 “a” 函数 func() 数组 array()
- 数组和函数形式很像,所以需要实现定义清楚,否则不好区分
- 但是VB里,index用 () 而不是一般语言的 []
-
Sub t3()
-
Dim arr3(3) As Integer
-
arr4(1) = 1 '直接会报错,arr4未定义!!
-
End Sub
rem 变量可以赋初值,就可以表达式运算,不同的变量,默认初值不同
-
Sub t3()
-
rem 变量可以赋初值,就可以表达式运算,不同的变量,默认初值不同
-
a = a + 1
-
Debug.Print a
-
'arr4(1) = 1 '直接会报错,arr4未定义!!
-
End Sub
-
'selection
-
Sub 删除空格4()
-
Dim arr1()
-
ReDim arr1(11) '不redim呢
-
j = 0 'j=1开始就会越界
-
For i = 1 To 11 Step 1
-
If Not IsEmpty(Cells(i, 1)) Then
-
arr1(j) = Cells(i, 1)
-
j = j + 1
-
End If
-
Next i
-
For j = 0 To UBound(arr1())
-
Cells(j + 1, 9) = arr1(j) '单元格得从1开始,arr()得从0开始
-
Next j
-
End Sub
三 数组的 声明+ 赋值 不同方法
3.1 声明定义数组有3种方法:
- 直接声明数组
- 数组名为变量
- 数组名为对象名
3.2 数组名(变量名)与数组
- 变量名代表变量
- dim a
- 或者不声明 a 直接使用也默认为变量
- 数组名 与数组
- 如果先声明 dim arr1()
- arr1 就代表 arr1() 否则arr1 一般就被认为是变量名
- 函数名 与函数
- 如果先声明的 function func1()
- func1 就代表 func1()
3.3 数组不能被赋值,只有 数组的元素,变量,对象可以被赋值
- 而数组不能被直接赋值
- 只有数组的元素可以被赋值
- 而变量,对象都是可以被直接赋值的
-
Sub test001()
-
Rem VBA里的array是数组
-
Rem 数组不能被赋值,只能给数组的元素赋值
-
Rem Excel里的range是对象,2维数组对象 <> 数组,range是对象不是数组!
-
Rem 对象是可以被赋值的,赋值给了对象的 range.value属性
-
Dim arr1(3) '如果已经声明为数组名了,arr1就代表arr1(),以后就不能给数组赋值
-
Dim arr2 As Variant '相当于dim arr2
-
Dim arr3 As Object
-
'arr1 = Range("a1:c1") '不能给数组赋值? 只能给数组里的元素赋值?arr1 = Range("a1:c1").value 也不行
-
arr1(0) = Range("a1") '可以给数组的某个元素赋值
-
arr2 = Range("a1:c1") '可以给变量赋值,赋予这个变量整个数组
-
Set arr3 = Range("a1:c3") '可以把EXCEL的range 赋值给变量,或对象。然后默认都成为了2维数组。
-
Range("b2:c2") = 9999
-
Debug.Print "arr1(0)=" & arr1(0)
-
Debug.Print "arr2(1,1)=" & arr2(1, 1)
-
Debug.Print "arr3(1,1)=" & arr3(1, 1)
-
End Sub
四 数组定义和赋值
4.1 数组的 声明/定义大小 和赋值 ----数组使用前需要定义数组大小
- Dim Array
- Dim Array()
- Dim array as object
- 无差别??--是不是有点太随便了,反而不好学规律
- 声明数组的时候
- 无论dim arr1 (as variant)
- 还是 dim arr1()
- 但是一旦 dim arr1 as object就有问题,数组不是对象? 报错 缺少数组
- 但是一旦 dim arr1() as object就有问题,数组不是对象? 报错缺少数组
总结:这2种没差别
- dim arr1 或 dim arr1() 都可以
- arr1=range 或 arr1()=range 都可以
-
Sub 测试1()
-
Dim arr1 As Variant
-
arr1 = Range("a1:c4") '这里为什么不 set 为对象呢?
-
Debug.Print arr1(3, 3)
-
Debug.Print LBound(arr1)
-
Debug.Print UBound(arr1)
-
Debug.Print LBound(arr1, 2) '二维数组,第1维默认是行数,往下数!
-
Debug.Print UBound(arr1, 2) '二维数组, array(row,column)
-
Sub 测试2()
-
Dim arr2()
-
arr2 = Range("a1:c4")
-
Debug.Print arr2(3, 3)
-
Debug.Print LBound(arr2)
-
Debug.Print UBound(arr2)
-
Debug.Print LBound(arr2, 2)
-
Debug.Print UBound(arr2, 2)
-
End Sub
-
Sub 测试3()
-
Dim arr2()
-
arr2() = Range("a1:c4")
-
Debug.Print arr2(3, 3)
-
Debug.Print LBound(arr2)
-
Debug.Print UBound(arr2)
-
Debug.Print LBound(arr2, 2)
-
Debug.Print UBound(arr2, 2)
-
End Sub
-
End Sub
4.2 array() 函数的作用----再升高一维数组
-
Sub 测试1()
-
Dim arr1 '定义arr1() 其实arr1就代表了数组把 arr1()只是明晰了声明了arr1是数组
-
arr1 = Array(Range("a1:a4"), Range("b1:b4"), Range("c1:c4"))
-
Rem array()转的都是1维数组把, no 这里是三维数组
-
Rem array 只是加一维,并非是转成1维数组了
-
Debug.Print arr1(0)(1)(1)
-
For i = 1 To UBound(arr1)
-
Debug.Print arr1(i)(2)(1) '写成arr(i)会报类型不匹配,因为数组维数不对
-
Next i
-
End Sub
4.3 关于dim array() 的index下标
- array 使用前,必须先定义 dim array() 大小
- 无论是静态的数组,或是静态的大小 dim array(10) 或 redim array()
- 首先要记住,cells()等是excel对象,其pos是(row column)组成,所以下标必须从1开始,不能从开始
- 而array() 默认index都是从0开始, 比如这么定义 dim arr1(4,3) 实际上是 arr1(0 to 4, 0 to 3)
- 但是array的index下标可以从1 或者2 等其他开始
- 比如 dim array1(1 to 5) dim array2(2to7)
- 一般为了两者匹配,所以定义数组维度时会这么定义
- arr1(1 to 4, 1 to 3) 完全是为了方便和excel对象的数据匹配
- 所以下面两种写法都可以,如果用array的index从0开始则需要注意,对应匹配好excel对象的 下标+1 和ubound -1
-
Sub 测试2()
-
Dim arr1(4, 3)
-
For i = 0 To 3
-
For j = 0 To 2
-
arr1(i, j) = Cells(i + 1, j + 1)
-
Debug.Print arr1(i, j)
-
Next j
-
Next i
-
Debug.Print vbCrLf ‘测试脚手架,不是一直有
-
Debug.Print arr1(0, 0)
-
End Sub
- 下面这么严格和excel对应也是OK的,一般人会这么写,
- 但要明白 array() 不严格声明下标 1 to 4 默认都会是 0 to 4,要明白这个!!
- 但是因为没有arr1(0,0) 所以Debug.Print arr1(0, 0) 会报错!
-
Sub 测试3()
-
Dim arr1(1 To 4, 1 To 3)
-
For i = 1 To 4
-
For j = 1 To 3
-
arr1(i, j) = Cells(i, j)
-
Debug.Print arr1(i, j)
-
Next j
-
Next i
-
Debug.Print vbCrLf
-
End Sub
- 但是如果含糊写,又不对应,也没问题
- 只是要知道。Arr1(0,0) 这里实际是没被赋值的,只是VBA这里没事。
- Debug.Print arr1(0, 0) 不会打印出东西 none 也不报错
-
Sub 测试4()
-
Dim arr1(4, 3)
-
For i = 1 To 4
-
For j = 1 To 3
-
arr1(i, j) = Cells(i, j)
-
Debug.Print arr1(i, j)
-
Next j
-
Next i
-
End Sub
五 数组分类
5.1 静态数组
- 静态数组定义的语法:
- dim arr1(10) as string 资料说是从1开始,我测试是从0开始
- 但是0~10都不越界,不是有11个数了? 就是0-11?
- dim arr2(5 to 10) as string
- 另外,数组数据类型也并不需要都是 as string, 测试 as integer同样没问题
-
Sub t3()
-
Dim arr(10) As String
-
For i = 1 To 10 Step 1
-
arr(i) = i
-
Debug.Print (arr(i))
-
Next i
-
Debug.Print arr(5)
-
Debug.Print arr(0) '不显示下标越界
-
Debug.Print arr(11) '会显示下标越界
-
End Sub
-
Sub t3()
-
Dim arr(10) As Integer
-
For i = 1 To 10 Step 1
-
arr(i) = i
-
Debug.Print (arr(i))
-
Next i
-
Debug.Print arr(5)
-
Debug.Print arr(0) '不显示下标越界
-
End Sub
5.2 动态数组
- 动态数组定义
- dim arr3() as string 或 dim arr3()
- 数组重定义:redim
- 只能重定义动态数组! 也必须重定义大小! 不redim前无法使用
- redim时,下标可以是变量
-
Sub t3()
-
Dim arr3() As Integer '如果定义dim arr3 as integer 会成为一个变量
-
Dim arr4() As Integer
-
For i = 1 To 5 Step 1
-
ReDim arr3(1 To i) '使用数组的内容之前,必须先redim 否则会显示下标越界
-
ReDim arr4(1 To i)
-
arr3(i) = i
-
arr4(i) = i
-
Debug.Print (arr3(i))
-
Debug.Print (arr4(i))
-
Next i
-
End Sub
-
Sub t3()
-
Dim arr5(1 To 5) As Integer
-
ReDim arr5(1 To 10) As String '不能对静态数组redim改变大小
-
End Sub
5.3 定义数组指向EXCEL对象,是二维数组,不能这么使用arr(1)
- 指向excel对象,比如range() 的 默认为2维数组,因为EXCEL表本身就是二维数组!
- 二维数组的下标,需要用excel里的r1c1模式
- 因为是二维数组,不能这么使用,即使只是1行或者1列数,但仍然是二维数据结构!
- arr1()=range("a1:e1") 虽然看起来只是a1 b1 c1 d1 e1 这5个数,但由于是在excel表里的对象,是二维的
-
Sub t3()
-
Rem Dim arr6 As Integer
-
arr6 = Range("a1:a5")
-
Debug.Print arr6(1, 1)
-
Debug.Print arr6(2, 1)
-
Debug.Print arr6(3, 1)
-
Debug.Print arr6(4, 1)
-
Debug.Print arr6(5, 1)
-
End Sub
六 定义二维数组
6.1 定义
- 定义方法
- dim arr1(4,5) as string
- dim arr1 (0 to 4,0 to 5) as integer
-
Sub t4()
-
Dim arr1(0 To 4, 0 To 5) As Integer
-
arr1(0, 0) = 999
-
Debug.Print arr1(0, 0)
-
End Sub
6.2 动态数组和静态数据的语法不要混用!
- 静态数组就不要再redim
- 动态数据就一定需要redim
-
Sub t4()
-
Dim arr2()
-
Rem Dim arr2(5, 6) '使用动态数组 redim就不要和 静态数组定义格式混用
-
For i = 0 To 5 Step 1
-
For j = 0 To 6 Step 1
-
ReDim arr2(0 To i, 0 To j) '动态数组,必须在使用前redim
-
arr2(i, j) = i + j
-
Debug.Print arr2(i, j)
-
Next j
-
Next i
-
Sub t4()
-
Dim arr2(5, 6)
-
For i = 0 To 5 Step 1
-
For j = 0 To 6 Step 1
-
Rem ReDim arr2(0 To i, 0 To j) '如果要用静态数组也可以,但不要再redim了!
-
arr2(i, j) = i + j
-
Debug.Print arr2(i, j)
-
Next j
-
Next i
-
End Sub
七 定义三维数组
- 下标也是从0开始的
-
Sub t4()
-
Dim arr3(3, 4, 5)
-
arr3(0, 0, 0) = 888
-
Debug.Print arr3(0, 0, 0)
-
End Sub
多维数组的问题---3维数组的表达方式???
- 到底哪种指定维度的方法正确?
- arr(1,2)
- arr(1)(2)
- 现在实际测试的结果是
- arr可以定位为变量,赋值为一个range 或 range.value,等价
- 但是没有 array().value 这种用法
- 现在实际测试的结果是
- 2维数组,只能arr(1,2)
- 3维数组,有的arr(1,2,3) 有的arr(1)(2)(3)
-
三维数组的表示问题,和之前的不同了
-
Sub test_3d()
-
Dim arr1(1 To 2)
-
Dim arr2(1 To 2, 1 To 2)
-
Dim arr3(1 To 2, 1 To 2, 1 To 2)
-
Dim arr4
-
arr1(1) = 1
-
arr2(1, 1) = 10
-
arr3(1, 1, 1) = 100
-
'arr4(1)(1)(1) = 100 为啥现在这么写不行了?莫不是偏移3次?对比之前的
-
Debug.Print arr1(1)
-
Debug.Print arr2(1, 1)
-
Debug.Print arr3(1, 1, 1)
-
'Debug.Print arr4(1)(1)(1)
-
End Sub
-
Sub test1()
-
Dim arr1
-
Dim arr2
-
Dim arr3
-
Dim arr4
-
Dim arr5(3, 4, 5)
-
arr1 = Range("b1:b3")
-
Debug.Print arr1(3, 1)
-
'Debug.Print arr1(3)(1)
-
arr2 = Range("b1:b3").Value
-
Debug.Print arr2(3, 1)
-
'Debug.Print arr2(3)(1)
-
arr3 = Array(Range("a1:a3"), Range("b1:b3"))
-
'Debug.Print arr3(0, 1, 1)
-
Debug.Print arr3(1)(1)(3)
-
'arr4 = Array(Range("a1:a3"), Range("b1:b3")).Value '报错
-
''Debug.Print arr4(0, 1, 1)
-
'Debug.Print arr4(1)(1)(3)
-
arr5(0, 0, 0) = 111
-
Debug.Print arr5(0, 0, 0)
-
'Debug.Print arr5(0)(0)(0)
-
End Sub
https://zhidao.baidu.com/question/504144613.html
要点:
-
取特定区间的数[a,b)表示为Int((b * Rnd) + a)
-
rnd本指取[0,1)之间的数
-
Randomize 语句初始化随机数生成器。 语法 Randomize [number] 可选的 number 参数是 Variant 或任何有效的数值表达式。 说明 Randomize 用 number 将 Rnd 函数的随机数生成器初始化,该随机数生成器给 number 一个新的种子值。如果省略 number,则用系统计时器返回的值作为新的种子值。 如果没有使用 Randomize,则(无参数的)Rnd 函数使用第一次调用 Rnd 函数的种子值)
-
四舍五入函数Round(x1[,x2]) 四舍五入保留小数x2位,省略表示为取整
代码区
-
猜数游戏
如果不使用Randomize,则随机数第一次写入内存后就不会更改,下次运行 值不变。Randomize重在可以初始化内存中的随机数值