分享

VBA进阶 | 数组基础09: 使用数组作为过程参数及从函数返回数组

 L罗乐 2017-12-05


本文系因违规而删除的2017年10月31日推送文章经修改后重新推送,已看过的朋友可直接飘过,免得浪费时间。

 

VBA中,可以使用数组作为过程的参数,也可以从函数过程返回数组,这是一项很有用的技术。

 

使用数组作为过程的参数

可以传递数组作为过程的参数,如下面的示例代码:

Sub test()

    Dim myArray(2) As Long

    Dim iCount As Integer

    Dim str As String

   

    myArray(0) = 1

    myArray(1) = 2

    myArray(2) = 3

   

    testPassArray passArray:=myArray

   

    For iCount = LBound(myArray) ToUBound(myArray)

        str = str & 'myArray('& iCount & ') = ' & myArray(iCount) & vbCr

    Next iCount

   

    MsgBox str

End Sub

 

SubtestPassArray(ByRef passArray() As Long)

    Dim i As Long

    For i = LBound(passArray) ToUBound(passArray)

        passArray(i) = (i 1) * 100

    Next i

End Sub

在代码中:

  • 将数组myArray传递到被调用的testPassArray过程,在该过程中,数组经过处理后,最后的结果如图1所示。

 1

  • 注意到testPassArray过程名后的关键字ByRef,表明数组是通过引用传递的,这样,在被调用过程中对数组的修改都是对实际所传递的数组的修改,从图1所示的结果中我们也可以看出来。

  • 在调用过程中的数组的数据类型与被调用过程中传递给的参数中的数组的数据类型要相匹配,如本例中的数组myArraypassArray都是Long型。不能简单地将被调用过程的参数声明为Variant型,想当然地认为可以接受任意类型的数组。

 

下面演示传递动态数组给被调用函数的示例代码:

SubtestDynamicArray()

    Dim DynArray() As Double

    Dim iCount As Long

    Dim str As String

   

    '调用PopulateArray过程来调整数组大小并填充相应的数据

    PopulateArray myArray:=DynArray,testRange:=Range('A2:A9'), strName:='张三'

   

    str = '张三的测试成绩分别为: '

    For iCount = LBound(DynArray) ToUBound(DynArray)

        str = str & vbCr &DynArray(iCount)

    Next iCount

   

    MsgBox str

End Sub

 

SubPopulateArray(ByRef myArray() As Double, testRange As Range, strName As String)

    Dim rng As Range

    Dim iIndex As Long

   

    If testRange Is Nothing Then

        MsgBox '单元格区域为空!'

        Exit Sub

    End If

   

    '重新定义动态数组的大小为整个单元格区域的单元格数

    ReDim myArray(1 To testRange.Cells.Count)

   

    '遍历单元格区域,找到相应的单元格后将对应值存储到数组中

    For Each rng In testRange.Cells

        If rng.Value = strName Then

            iIndex = iIndex 1

            myArray(iIndex) = rng.Offset(0,1).Value

        End If

    Next rng

   

    '重新定义数组大小为已填充的元素数

    ReDim Preserve myArray(1 To iIndex)

End Sub

在代码中:

  • 在主调过程testDynamicArray中声明了动态数组DynArray(),并将其传递给被调过程PopulateArray。在被调过程PopulateArray中,根据实际需要调整大小。

  • 注意到,在被调过程PopulateArray中,我们首先将数组大小调整为可能的最大值,待填充完数据后,再将其调整为实际大小。这样,避免了每次增加数据时都要重新调整数组大小而导致会发生的可能问题。

  • 注意,在被调用过程的参数列表中声明数组时,不能包括大小。

  • 上述代码运行的结果如图2所示。

 2

 

下面的示例传递固定大小的静态数组到Function过程:

SubtestPassArrayToFunction()

    Dim myArray(1 To 3) As Long

    Dim lngResult As Long

   

    myArray(1) = 10

    myArray(2) = 20

    myArray(3) = 30

   

    result = SumToArray(passArray:=myArray)

    MsgBox result

End Sub

 

FunctionSumToArray(passArray() As Long) As Long

    Dim iCount As Integer

    Dim lngTotal As Long

   

    For iCount = LBound(passArray) ToUBound(passArray)

        lngTotal = lngTotal passArray(iCount)

    Next iCount

   

    SumToArray = lngTotal

End Function

在代码中:

  • 主过程testPassArrayToFunction调用SumToArray过程并传递需要求和的数组,SumToArray过程对接收到的数组求和并返回结果。

  • 前面我们讲过,在调用过程中的数组的数据类型与被调用过程中传递给的参数中的数组的数据类型要相匹配。然而,有时可能不知道传递的数组的类型,那该如何做呢?

如果要传递任意类型的数组,那么在被调用过程的参数声明中不要将要接收数组的参数声明为数组,而应该声明为Variant型。例如,将上述Function过程修改如下,使其可以接收其他类型的数组数据。

FunctionSumToArray1(passArray As Variant)

Dim iCount As Integer

Dim lngTotal As Long

   

If IsArray(passArray) Then

        ForiCount = LBound(passArray) To UBound(passArray)

            lngTotal = lngTotal passArray(iCount)

        Next iCount

End If

SumToArray = lngTotal

End Function

 

从函数返回数组

下面的示例演示从函数返回一个数组:

SubtestReturnArray()

    Dim myArray() As Long

    Dim iCount As Long

   

    myArray = LoadNumbers(Low:=21, High:=30)

   

    For iCount = LBound(myArray) To UBound(myArray)

        Debug.Print myArray(iCount)

    Next

End Sub

 

FunctionLoadNumbers(Low As Long, High As Long) As Long()

    Dim resultArray() As Long

    Dim lngIndex As Long

    Dim lngVal As Long

   

    If Low > High Then

        Exit Function

    End If

   

    ReDim resultArray(1 To (High - Low 1))

    lngVal = Low

   

    For lngIndex = LBound(resultArray) ToUBound(resultArray)

        resultArray(lngIndex) = lngVal

        lngVal = lngVal 1

    Next lngIndex

   

    LoadNumbers = resultArray()

End Function

在代码中:

  • 接收数组结果的变量(如示例中的myArray())必须是动态数组,并且必须与返回的数组有相同的数据类型(如示例中的Long),或者声明为Variant变量(例如,Dim myArray As Variant)。

  • 如果接收数组结果的变量(如示例中的myArray())是静态数组,那么函数返回值的数组必须是动态数组,它将自动调整大小来返回合适的数组。

  • 如果接收数组与返回的数组的下标索引的基准值不同,那么将使用返回的数组的下标索引基准值。

 

将一个数组赋值给另一个数组

VBA不允许将一个数组直接赋给另一个数组,即便其大小和数据类型都一致。例如,下面的代码:

Dim A(1 To 10) AsLong

Dim B(1 To 10) AsLong

A = B

运行代码后将产生编译错误:不能给数组赋值。

 

然而,可以将包含数组的Variant型变量赋值给另一个Variant型变量,例如下面的代码:

Dim A As Variant

Dim B As Variant

Dim i As Long

A = Array(11, 22,33)

B = A

 

通常情况下,想要将一个数组的内容转移到另一个数组中,就必须遍历数组并逐元素赋值:

Dim A(1 To 3) AsLong

Dim B(0 To 5) AsLong

Dim lngIndexA AsLong

Dim lngIndexB AsLong

 

A(1) = 11

A(2) = 22

A(3) = 33

lngIndexB =LBound(B)

 

For lngIndexA =LBound(A) To UBound(A)

    If lngIndexB <= UBound(B) Then

        B(lngIndexB) = A(lngIndexA)

    Else

        Exit For

    End If

    lngIndexB = lngIndexB 1

Next lngIndexA

注意到,上面代码中数组AB的维数不同,数组B的维数大于数组A的维数。如果数组A的维数大于数组B的维数,则当数组BUBound达到时循环终止。


相关链接:

VBA进阶 | 数组基础01: 用最浅显的介绍来帮助你认识数组

VBA进阶 | 数组基础02: 简单的数组操作

VBA进阶 | 数组基础03: 二维数组

VBA进阶 | 数组基础04: 运用数组处理工作表数据

VBA进阶 | 数组基础05: 动态数组

VBA进阶 | 数组基础06: 与数组相关的函数——Array函数与IsArray函数

VBA进阶 | 数组基础07: 与数组相关的函数——Split函数与Join函数

VBA进阶 | 数组基础08: 与数组相关的函数——Filter函数



 

本文整理自cpearson.com,转载请注明出处。

欢迎在下面留言,完善本文内容,让更多的人学到更完美的知识。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多