我在 Excel 中为一个名称分配了一个公式,计算速度很慢。
假设是这样的:
Name: ImportantItems
Scope: Workbook
RefersTo: =FILTER(A1:A10000, complexCondition(A1:A10000))
我有一些 VBA 宏,它们运行模拟,在每次迭代时修改 A1:A10000,但是模拟只需要每 100 次迭代访问 ImportantItems
数组。如果
=FILTER(A1:A10000,complexCondition(A1:A10000))
...是单元格中的正常公式,我知道Excel会观察到其先例(A1:A10000)已更改并在每次迭代时触发重新计算。不过,我希望电子表格中任何地方都没有引用的命名范围(仅通过 VBA)将根据需要进行计算。 FWIW我的VBA代码只是
Dim items As Variant 'read fancy filtered array of stuff into 1D array
items = Application.Transpose(Sheet1.Range("ImportantItems").Value)
我的替代方案是重构ImportantItems 代码并将其移至VBA 中,以便我可以控制计算时间。 Application.Calculations = xlManual
不是一个选项,除非在我的代码中添加...
无论如何,这并不是一个 A/B 问题,我只是想知道计算引擎是如何工作的,因为我找不到相关文档,它将影响 future 的设计决策。
最佳答案
您的希望/假设是正确的。只要工作簿中的任何范围均未引用指定范围(其他指定范围不算在内),则当源范围更改时,不会重新计算指定范围中的公式。
它不重新计算的原因是命名范围存储公式字符串(请参阅 VBA 中的 Name
对象 .RefersTo
)。仅当从对公式字符串运行 Evaluate 的范围引用命名范围时,Excel 才会传播更改(在源中)。当调整源大小(剪切/插入/删除单元格)时,命名范围公式字符串会更新,但本质上它仍然是一个字符串。
要进行测试,请创建以下命名范围:
名称:TestCalc
范围:Sheet1
引用:=NamedRangeWatch(Sheet1!$A$1:$A$5)
然后在标准 .bas VBA 模块中添加以下代码:
Option Explicit
Public Function NamedRangeWatch(ByVal rng As Range) As Range
Application.Volatile False
Debug.Print "NamedRangeWatch was called at " & Now
Set NamedRangeWatch = rng
End Function
Sub Test()
Dim i As Long
For i = 1 To 10
Sheet1.Range("A1:A5").Value2 = i
If i Mod 5 = 0 Then
Debug.Print Application.Sum(Sheet1.Names("TestCalc").RefersToRange)
'Or
'Debug.Print Application.Sum(Sheet1.Range("TestCalc").Value)
End If
Next i
End Sub
然后运行Test
方法。您应该看到类似以下内容:
这表明,尽管源范围更改了 10 次,但命名范围内的函数仅被调用两次。
关于excel - 动态命名范围/公式多久重新计算一次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67883258/