Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays VBA-通过应用程序计算长数组公式_Arrays_Vba_Excel_Excel Formula - Fatal编程技术网

Arrays VBA-通过应用程序计算长数组公式

Arrays VBA-通过应用程序计算长数组公式,arrays,vba,excel,excel-formula,Arrays,Vba,Excel,Excel Formula,假设我们在单元格A1中保存了一些长公式: =SomeArrayFunction( IF(SUM(D3:D6)>1,"A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X 01", "part_one"), IF(SUM(D3:D6)>1,"A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X 02", IF(SUM(D3:D6)>1,"A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-

假设我们在单元格A1中保存了一些长公式:

=SomeArrayFunction(
IF(SUM(D3:D6)>1,"A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X 01",
"part_one"),
IF(SUM(D3:D6)>1,"A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X 02",
IF(SUM(D3:D6)>1,"A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X 03",
"part_two"))
)
它使用以下VBA函数

Public Function SomeArrayFunction(sOne As String, sTwo As String) As Variant
    Dim V() As Variant
    ReDim V(1 To 2, 1 To 1)
    V(1, 1) = sOne
    V(2, 1) = sTwo
    SomeArrayFunction = V
End Function
Public Sub EvaluateFormula()
    Dim vOutput As Variant

    vOutput = Application.Evaluate(Selection.Formula)

    If VarType(vOutput) >= vbArray Then
        MsgBox "Array:" & vbCrLf & vOutput(1, 1) & vbCrLf & vOutput(2, 1)
    Else
        MsgBox "Single Value: " & vbCrLf & vOutput
    End If
End Sub
返回一个2×1数组


现在当我调用这个VBA函数

Public Function SomeArrayFunction(sOne As String, sTwo As String) As Variant
    Dim V() As Variant
    ReDim V(1 To 2, 1 To 1)
    V(1, 1) = sOne
    V(2, 1) = sTwo
    SomeArrayFunction = V
End Function
Public Sub EvaluateFormula()
    Dim vOutput As Variant

    vOutput = Application.Evaluate(Selection.Formula)

    If VarType(vOutput) >= vbArray Then
        MsgBox "Array:" & vbCrLf & vOutput(1, 1) & vbCrLf & vOutput(2, 1)
    Else
        MsgBox "Single Value: " & vbCrLf & vOutput
    End If
End Sub
选择单元格A1时,我遇到一个错误,因为Application.Evaluate无法处理超过255个字符的公式(例如,请参阅)。另一方面,如果我写

vOutput = Application.Evaluate(Selection.Address)
相反(正如上面链接中所建议的那样),它工作得很好。除了数组不再被重新格式化的事实,即调用MsgBox“Single Value:”而不是MsgBox“array:”

所以我的问题是:如何使用VBA计算长公式(返回数组)


编辑:让我强调,当我只选择包含公式的一个单元格时(不是一个区域或多个单元格),我需要这样做。我没有将其作为数组公式输入(即,没有花括号):


Edit2:让我来回答为什么:我目前的工作要求我在电子表格中有一长串如此大的公式。而且,由于它们被组织在一个列表中,因此每个这样的公式只能占用一个单元格。在几乎所有情况下,公式都返回单个值(因此一个单元格足以存储/显示输出)。但是,当计算公式时出现内部错误时,公式将返回错误消息。这些错误消息通常很长,因此返回的数组大小不同(取决于错误消息的长度)。因此,我的目标是编写一个VBA函数,该函数将首先获取并输出列表中给定选定项的完整错误消息。

试试看

 vOutput = Application.Evaluate(Selection.CurrentArray.Address)
(假设有两个单元格,
=SomeArrayFunction(…)
作为数组公式输入)


我认为不同之处可能在于,对单个单元格求值只会得到返回到该单元格的值:整个数组不会在那里返回,只返回第一个值。

我相信
Application.Evaluate
将返回与输入地址大小匹配的结果。我怀疑您的
选择
是单个单元格,因此它返回单个值

如果改为使用
Selection.CurrentArray.Address调用它,您将得到与正确数组大小相同的答案

VBA和Excel的图片

要测试的代码

Public Function Test() As Variant

    Test = Array(1, 2)


End Function

Sub t()

    Dim a As Variant

    a = Application.Evaluate(Selection.CurrentArray.Address)

End Sub
编辑,根据评论,这里是一种通过创建新工作表来评估此表外文件的方法。我使用剪切/粘贴方法来确保所有公式的工作原理相同。如果单元格不引用切割的单元格,这可能会更好。但从技术上讲,它不会破坏任何其他单元格,因为我使用的是剪切/粘贴

在下面的代码中,我在单元格J2中有一个数组公式,它引用了其他几个单元格。它被扩展为3行,然后进行
Evaluate
调用。返回所需的数组。然后将其缩小为一个单元格,并将其移回

我已经测试了一个简单的例子。我不知道它是否适用于您心目中的应用程序

Sub EvaluateArrayFormulaOnNewSheet()

    'cut cell with formula
    Dim str_address As String
    Dim rng_start As Range
    Set rng_start = Sheet1.Range("J2")
    str_address = rng_start.Address

    rng_start.Cut

    'create new sheet
    Dim sht As Worksheet
    Set sht = Worksheets.Add

    'paste cell onto sheet
    Dim rng_arr As Range
    Set rng_arr = sht.Range("A1")
    sht.Paste rng_arr

    'expand array formula size.. resize to whatever size is needed
    rng_arr.Resize(3).FormulaArray = rng_arr.FormulaArray

    'get your result
    Dim v_arr As Variant
    v_arr = Application.Evaluate(rng_arr.CurrentArray.Address)

    ''''do something with your result here... it is an array


    'shrink the formula back to one cell
    Dim str_formula As String
    str_formula = rng_arr.FormulaArray

    rng_arr.CurrentArray.ClearContents
    rng_arr.FormulaArray = str_formula

    'cut and paste back to original spot
    rng_arr.Cut

    Sheet1.Paste Sheet1.Range(str_address)

    Application.DisplayAlerts = False
    sht.Delete
    Application.DisplayAlerts = True

End Sub

我忙于排列Excel、VBA编辑器和那个监视窗口,无法及时得到答案。我同意这种观点,即它只是评估单个细胞。这也是一个有趣的行为。也许这有助于解释为什么它需要这样工作。我更喜欢你的版本-@Tom-你应该接受这个。我想这可能是一个打破骆驼背的版本。Excel通过Eval很好地处理了超过255个字符的数组公式,但可能不是单个单元格。我会回应@TimWilliams:为什么?使用单元格来存储计算结果大于其容器的数组公式,然后通过单元格通过“计算”访问VBA中的该对象,以获取比Excel存储的信息更多的信息,这似乎非常迂回。是否有理由不在VBA中使用公式,因为单元格似乎与解决方案无关,只是为了保存公式?我们缺少什么?@TimWilliams和Byron:我在我的问题中添加了一个为什么。谢谢你的为什么。现在这变得有趣了。阅读您的描述后,我的第一个想法是:您能在当前列(“列表”)旁边的列中输入数组公式吗?您可以对公式调用
TRANSPOSE
,将列转换为行。这有点“脏”,但如果足够大,可以捕获所有错误输出,则可以将它们全部设置为10个单元格宽。我真的认为,如果没有类似于公式数组的东西,就不会得到数组输出。问题是如何最好地做到这一点。您的错误消息的长度是否真的超过32k(或者您是否试图绕过单元格内的显示限制)?在任何情况下,似乎都可以使用“scratch”范围来放置公式,然后对其进行求值。@Byron:我也想过将其转置,但通常我有几个列表彼此相邻,这使得这种方法不可能。@TimWilliams:消息并不庞大,但是,如果错误字符串的长度超过某个阈值,公式只返回数组(我无法更改这些公式,使它们返回比数组更长的字符串)。我的一个想法是在VBA中创建一个空的虚拟工作表对象,然后将公式复制到其中。然后,我可能会执行下面讨论的方法。但我没有足够的经验来判断这是否是一种可行的方法。