Arrays VBA-通过应用程序计算长数组公式
假设我们在单元格A1中保存了一些长公式: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-
=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中创建一个空的虚拟工作表对象,然后将公式复制到其中。然后,我可能会执行下面讨论的方法。但我没有足够的经验来判断这是否是一种可行的方法。