如何将一个固定数组传递并循环到VBA中的函数?

时间:2016-09-13 21:17:37

标签: arrays excel vba excel-vba function

我的功能涉及一个范围,比如无风险的利率,并产生一系列折扣因子。问题似乎在循环中,有三个:

(a)在阵列上调用fn,
(b)指定阵列点,
(c)使用循环i作为fn参数。

是在每个数组周围使用循环的最佳方法(第i点),还是可以通过简单地调用函数来填充完整数组?

Function CreateDiscArray(RFR_array As Range)

    Dim MyArray() As Variant
    MyArray = RFR_array

    Dim xDimRate As Integer
    xDimRate = UBound(MyArray, 1)

    Dim TempArray() As Variant
    For i = 1 To xDimRate Step 1
        TempArray(i, 1) = DiscFact(MyArray(i), i)
    Next i

    CreateDiscArray() = TempArray()
End Function

Function DiscFact(Rate, Tenor)
    If Tenor < 1 Then DiscFact = (1 + Tenor * Rate)
    If Tenor >= 1 Then DiscFact = (1 + Rate) ^ (-Tenor)
End Function

即。是否可以在没有循环的情况下调用:

CreateDiscArray = DiscFact(MyArray(,1), 1 to xDimRate)

1 个答案:

答案 0 :(得分:4)

您的原始代码存在一些问题

  • 您没有使用Option Explicit,因此您不知道i未声明。

  • 您没有确定TempArray的尺寸,因此您的代码无法分配给其索引。

  • 您引用的myArray(i)会因为有2个维度而失败,因此您必须使用myArray(i,1)

  • 您正在使用i计数器(基于1)作为男高音。这是一个糟糕的设计选择,因为你的男高音并不总是一致的长度,你可以期待有很多短期的男高音。此外,这是一个错误,因为i >= 1 总是TRUE

因此,要使原始函数可行代码

Option Explicit

Function CreateDiscArray(RFR_array As Range)

    Dim MyArray() As Variant
    MyArray = RFR_array.Value

    Dim xDimRate As Integer
    xDimRate = UBound(MyArray, 1)

    ReDim TempArray(LBound(MyArray) To UBound(MyArray), LBound(MyArray, 2) To UBound(MyArray, 2)) As Variant
    Dim i As Long
    For i = 1 To xDimRate Step 1
        TempArray(i, 1) = DiscFact(MyArray(i, 1), i)
    Next i

    CreateDiscArray = TempArray
End Function

Function DiscFact(Rate, Tenor)
    'BUG: Tenor will always be >= 1
    If Tenor < 1 Then DiscFact = (1 + Tenor * Rate)
    If Tenor >= 1 Then DiscFact = (1 + Rate) ^ (-Tenor)
End Function

但那不是你的问题。正如其他人所指出的那样,VBA本身并不支持任何东西,但你使用的是Excel,所以你确实有一些选择:

首先,让我们通过在tenors之外添加一系列rates来修复Tenor错误。期待在A1:A3,费率在B1:B3。我们可以将C1:C3中的数组公式用作=IF(A1:A3<1,1+A1:A3*B1:B3,(1+B1:B3)^(-A1:A3))

    A   |   B  |   C
--+-----|------|-------------------------------------------------
1 | .5  | 99   | {=IF(A1:A3<1,1+A1:A3*B1:B3,(1+B1:B3)^(-A1:A3))}
2 | 1   | 97   | 
3 | 2   | 95   | 

并且,如果您将命名范围命名为Tenor和Rate,则可以将数组公式重新定义为=IF(Tenor<1,1+Tenor*Rate,(1+Rate)^(-Tenor))

如果您确实希望此解决方案位于VBA中,则需要更改功能签名以接受期限费率范围,然后使用Application.Evaluate以及构造的公式,获得一系列结果。

使用笨拙的解决方案,不关心工作表或工作簿:

Public Function DiscFactor(rates As Range, tenors As Range) As Variant

  Dim Rate As String
  Dim Tenor As String
  Rate = rates.Address
  Tenor = tenors.Address

  DiscFactor = Application.Evaluate("=IF(" & Tenor & "<1,1+" & Tenor & "*" & Rate & ",(1+" & Rate & ")^(-" & Tenor & "))")

End Function