【问题标题】:Excel VBA UDF Array function returns the same value for all celsExcel VBA UDF Array 函数为所有单元格返回相同的值
【发布时间】:2018-02-25 04:16:11
【问题描述】:

我正在尝试让我的 Excel VBA UDF 函数返回一个数组。截至目前,该函数要么返回#VALUE!如果我将参数定义为双精度数组,或者如果我将参数定义为变量,则即使我在 VBE 中检查了局部变量窗口并且返回数组变量实际上包含不同的值,则数组中的所有单元格都具有相同的值。

这是我的代码:

Function VaRScenariosTest(ByRef dblRealRates() As Double/Variant) As Double()
'dblRealRates() is defined as either Double or Variant
Dim intCount As Integer
Dim dblTemp() As Double

For intCount = LBound(dblRealRates) To (UBound(dblRealRates) - 1)
  ReDim Preserve dblTemp(1 To intCount)
  dblTemp(intCount) = dblRealRates(intCount + 1) - dblRealRates(intCount)
Next intCount

VaRScenariosTest = dblTemp

End Function

Function Range2dblArray(ByRef rngRange As Range) As Double()

Dim dblTemp() As Double
Dim intCount As Integer

For intCount = 1 To rngRange.Count
  ReDim Preserve dblTemp(1 To intCount)
  dblTemp(intCount) = rngRange.Cells(intCount)
Next intCount

Range2dblArray = dblTemp

End Function

我通过以下方式调用电子表格中的函数: function call in excel with dblRealRates() as Double/Variant

E 列包含函数的输入,F 列包含函数应返回的值,G 列包含函数本身。如果我将 dblRealRates() 变量类型定义为 double,则公式将返回 #VALUE!错误。如果我将其定义为变体,则电子表格中的返回值是相同的。 如果我在 End Function 行暂停代码的执行并查看 Locals WIndow,您实际上可以看到数组中的值是不同的,并非都等于 0.000016287,如电子表格中的输出所示:Function Array values in Locals Window

有人能告诉我为什么当 dblRealRates() 变量被定义为 double 时公式会返回错误,如果它被定义为变量,为什么它会返回相同的值?

【问题讨论】:

  • 有什么理由需要使用Range2dblArray 作为UDF?如果它不需要从 Excel 单元格中使用,事情会更容易,而且我不确定它作为独立的 Excel 函数有什么用途。如果它也不需要是 UDF,那么您可以将 Range 传递给 VaRScenariosTest,然后它可以调用 Range2dblArray 作为它做的第一件事。
  • VaRScenariosTest 函数是更大计算的中间步骤,因此它将 vba 变量作为参数而不是 Range 对象。但是出于测试目的,我希望能够查看所有中间步骤,因此我实现了Range2dblArray 函数以便能够将Range 对象传递给中间函数,我想在其中检查中间结果
  • 这似乎是为了避免使用 Locals Window 来查看中间结果。
  • 这是因为这个函数稍后会有更多的参数,因此需要测试这些参数的所有可能组合,这些参数可能是 100 或更多。对我来说,将参数放在单元格中会更容易,只需拖动公式以对应适当的单元格。它还可以让我更轻松地比较这些值。
  • 我仍然建议您不要将最终代码作为 UDF 工作。使用 UDF 作为一个简单的包装器,它只调用您的正确代码。这样,您只需要担心从 Excel 数据类型到您的内部数据类型的一层转换,而不是在您的每个函数中。

标签: arrays excel user-defined-functions vba


【解决方案1】:

一维数组被视为由 x 列组成的一行,这就是为什么你的值总是相同的原因。 (整个结果列都分配了返回的第一列的值。)

以下代码适用于您的情况(但如果您将内容更改为在行而不是列上工作,无疑会出现问题):

Function VaRScenariosTest(ByRef dblRealRates() As Variant) As Variant()
    Dim intCount As Integer
    Dim dblTemp() As Double

    For intCount = LBound(dblRealRates) To (UBound(dblRealRates) - 1)
        ReDim Preserve dblTemp(1 To intCount)
        dblTemp(intCount) = dblRealRates(intCount + 1, 1) - dblRealRates(intCount, 1)
    Next intCount

    VaRScenariosTest = Application.Transpose(dblTemp)
End Function

Function Range2dblArray(ByRef rngRange As Range) As Variant()
    Dim dblTemp() As Double
    Dim intCount As Integer

    For intCount = 1 To rngRange.Count
        ReDim Preserve dblTemp(1 To intCount)
        dblTemp(intCount) = rngRange.Cells(intCount)
    Next intCount

    Range2dblArray = Application.Transpose(dblTemp)
End Function

或者,通过在 Excel 公式本身中对 Range2dblArray 的结果进行转置

{=VaRScenariosTest(TRANSPOSE(Range2dblArray(E2:E21)))}

你可以保持原来的Range2dblArray不变,只修改VaRScenariosTest

Function VaRScenariosTest(ByRef dblRealRates() As Variant) As Variant()
    Dim intCount As Integer
    Dim dblTemp() As Double

    For intCount = LBound(dblRealRates) To (UBound(dblRealRates) - 1)
        ReDim Preserve dblTemp(1 To intCount)
        dblTemp(intCount) = dblRealRates(intCount + 1, 1) - dblRealRates(intCount, 1)
    Next intCount

    VaRScenariosTest = Application.Transpose(dblTemp)
End Function

Function Range2dblArray(ByRef rngRange As Range) As Double()
    Dim dblTemp() As Double
    Dim intCount As Integer

    For intCount = 1 To rngRange.Count
        ReDim Preserve dblTemp(1 To intCount)
        dblTemp(intCount) = rngRange.Cells(intCount)
    Next intCount

    Range2dblArray = dblTemp
End Function

并且还通过在 Excel 公式本身中对 VaRScenariosTest 的结果进行转置

{=TRANSPOSE(VaRScenariosTest(TRANSPOSE(Range2dblArray(E2:E21))))}

您可以允许VaRScenariosTest 也返回一个一维数组(但仍需要将dblRealRates 作为二维Variant 数组传递给函数):

Function VaRScenariosTest(ByRef dblRealRates() As Variant) As Double()
    Dim intCount As Integer
    Dim dblTemp() As Double

    For intCount = LBound(dblRealRates) To (UBound(dblRealRates) - 1)
        ReDim Preserve dblTemp(1 To intCount)
        dblTemp(intCount) = dblRealRates(intCount + 1, 1) - dblRealRates(intCount, 1)
    Next intCount

    VaRScenariosTest = dblTemp
End Function

Function Range2dblArray(ByRef rngRange As Range) As Double()
    Dim dblTemp() As Double
    Dim intCount As Integer

    For intCount = 1 To rngRange.Count
        ReDim Preserve dblTemp(1 To intCount)
        dblTemp(intCount) = rngRange.Cells(intCount)
    Next intCount

    Range2dblArray = dblTemp
End Function

【讨论】:

  • 我看到您将VaRScenariosTest 的变量类型从Double() 更改为Variant(),这是否意味着Double() 变量在这种情况下不起作用,即使我申请换位?我可以在函数的开头引入验证检查来检查维度,以避免在从行切换到列时出现问题,反之亦然。另外,你知道为什么函数返回#VALUE!当 dblRealRates() 变量定义为 double 时出错,即使 Range2dblArray 函数完全返回此类型(double 数组)?
  • @VBAEnthusiast 将数组返回到 Excel 后,Excel 将其转换为 Variant,然后将该 Variant 数组传递给您的函数。因为它无法处理转换回Double 并崩溃,所以UDF 返回#VALUE! 错误(这只是UDF 的说法“我崩溃了,我没有告诉你为什么!”)
【解决方案2】:

根据@YowE3K 的指导,最终确定了以下版本:

Function VaRScenariosTest(ByRef dblRealRates() As Variant) As Variant()
    Dim intCount As Integer
    Dim dblTemp() As Double

    For intCount = LBound(dblRealRates) To (UBound(dblRealRates) - 1)
        ReDim Preserve dblTemp(1 To intCount)
        dblTemp(intCount) = dblRealRates(intCount + 1) - dblRealRates(intCount)
    Next intCount

    VaRScenariosTest = Application.Transpose(dblTemp)
End Function

Function Range2Array(ByRef rngRange As Range) As Variant()
    Dim varTemp() As variant
    Dim intCount As Integer

    For intCount = 1 To rngRange.Count
        ReDim Preserve varTemp(1 To intCount)
        varTemp(intCount) = rngRange.Cells(intCount)
    Next intCount

    Range2Array = varTemp
End Function

在电子表格中使用时效果很好,如果我只想在 VBA 中使用,而不是在电子表格中使用,只有函数 VarScenariosTest 和数组参数 dblRealRates() 的数据类型必须改回双精度,虽然变体版本也可以在这里工作。 @YowE3K 谢谢你的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-26
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    相关资源
    最近更新 更多