前面讲了自定义函数的基本框架和如何传递不定参数,这一篇讲如何返回多个值。返回多个值,基本上就可以理解为返回数组。我们自定义的返回数组的函数,跟 Excel 自带的数组函数一样,需要按 Ctrl+Shift+Enter 输入。
在返回数组这件事上,我们需要决定返回的数组的维度。有下面几种情况:
第一种情况,返回一个大小固定的数组。
Function FixedFill() As Variant Dim N As Long Dim R As Long Dim C As Long N = 0 Dim V(1 To 3, 1 To 4) For R = 1 To 3 For C = 1 To 4 N = N + 1 V(R, C) = N Next C Next R FixedFill = V End Function
这个函数返回一个 3x4 大小的数组,值从 1 到 12。但是这个函数并没有什么应用价值,我们的返回值还是应该根据传入的参数或者输入函数的单元格范围的大小来变化。
第二种情况,根据输入函数的单元格范围大小来变化。也就是说,如果选了 A1:B2 这样 2x2 的范围来输入我们自定义的函数,我们返回的数组就是 2x2 大小;如果选了 C3:E8 这样 6x3 的范围来输入我们自定义的函数,我们返回的数组就是 6x3 大小。要获得输入函数的单元格范围的大小,我们可以用 Application.Caller 这个属性。当我们从表单单元格里调用函数时, Application.Caller 属性返回的是一个 Range 对象引用,表示输入该函数的单元格范围。
Function DynamicFill() As Variant Dim CallerRows As Long Dim CallerCols As Long Dim Result() As Long Dim N As Long Dim i As Long Dim j As Long N = 0 With Application.Caller CallerRows = .Rows.Count CallerCols = .Columns.Count End With ReDim Result(1 To CallerRows, 1 To CallerCols) For i = 1 To CallerRows For j = 1 To CallerCols N = N + 1 Result(i, j) = N Next j Next i DynamicFill = Result End Function
第三种情况,结合传入的参数和函数的目的来决定返回数组的维度。像我前一篇文章里的 MySum 函数,传入的虽然是个参数数组,但返回唯一的值。我这里举的一个例子,返回的数组大小根据传入的参数范围而变化。这个自定义函数是用来排序的,比如对员工年龄,学生分数等等。期望的参数是至少两列的单元格范围,参数的第一列是标识符,比如姓名,工号等等,参数的最后一列是要排序的数值。返回的数组为两列,行数根据传入的参数变化。返回数组的第一列即传入参数的第一列,返回数组的第二列即传入参数的最后一列,返回的数组里面的数据已经排过序。
Function MySort(cells As Range) Dim x As Integer Dim y As Integer Dim i As Integer Dim j As Integer Dim workCells() x = cells.Rows.Count y = cells.Columns.Count ReDim workCells(1 To x, 1 To 2) For i = 1 To x workCells(i, 1) = cells(i, 1) workCells(i, 2) = cells(i, y) Next i Dim temp For i = 2 To x temp = workCells(i, 2) j = i - 1 Do While (workCells(j, 2) > temp) workCells(j + 1, 2) = workCells(j, 2) workCells(j + 1, 1) = workCells(j, 1) j = j - 1 If j < 1 Then Exit Do End If Loop workCells(j + 1, 2) = cells(i, y) workCells(j + 1, 1) = cells(i, 1) Next i MySort = workCells End Function
最后补充一下,返回的数组应该定义为两维的,单维的数组在填充单元格的时候有问题。