【问题标题】:Storing rows of data in an array in a loop在循环中将数据行存储在数组中
【发布时间】:2021-02-28 10:58:04
【问题描述】:

我正在财务模型中运行模拟。对于每次模拟,我都会模拟一组变量,并将结果作为硬编码值存储在我的 Excel 工作簿中。

我想加快我的代码速度,并且已经阅读到写入工作簿是一个缓慢的过程。因此,我希望将每个模拟的结果变量存储在一个数组中,然后将数组写入最后的工作簿。

我可以用一个新循环填充行的每个单元格,但我相信这会使代码变慢。我浏览了许多帖子,但没有找到任何涵盖我的查询的帖子。

我想要这样的东西,但我不知道如何将一行数据写入数组。

Dim nSimulations As Integer
Dim nOutput_Variables As Integer
Dim myArray as Variant

'Assign Values
nSimulations = Range("QRA_Simulations").Value 'This will vary, but let's assume 100 simulations
nOutput_Variables = Range("QRA_Output_Copy").Column '25 output values

Redim myArray(nSimulations, nOutput_Variables) 'dimension array to have 100 rows and 25 columns

'Run loop
For iSim = 1 To nSimulations
    'Set simulation variables. 
    Range("QRA_OPEX").Value = Range("QRA_OPEX_Copy").Value
    Range("QRA_CAPEX").Value = Range("QRA_CAPEX_Copy").Value
    
    'Store simulation results as a row in my array
    myArray(iSim,0) = Range("QRA_Output_Copy").Value 'This does not work. The QRA_Output_Copy is a range spanning 1 row and 25 columns, holding 25 values.

Next iSim

Range("Output").Value = myArray 'This just returns #N/A. The output range is 100 rows and 25 colums

【问题讨论】:

  • 旁注 - 由于您对速度发表了评论并且正在运行金融模拟,我建议您查看 R 或 Python。根据经验,它们对于您尝试做的工作类型要“快速”得多,并且更容易扩展。我喜欢 excel 和 VBA,但您需要承认它在未来的局限性,尤其是对于您想要实现的目标。如果您只是进行原型设计,那么是的,VBA 就足够了,但是当您尝试扩展到更大的数据集时要小心。
  • 我很欣赏你的观点,我更愿意自己搬到 R。但是,我不是唯一使用财务模型的人,其他财务分析师不熟悉编码,所以我坚持使用 excel。
  • 如果您描述了QRA_Output_copy 范围的范围和最小样本内容以及您想要的输出形式,这将有助于提供帮助。 @JacobKorenBrekke
  • 在评论中更新了。
  • @T.M.正是我要找的,谢谢!也感谢小代码优化。

标签: arrays excel vba loops


【解决方案1】:

通过锯齿状数组(Array of arrays)接近

我假设您执行模拟,如更新同一输出行 QRA_Output_Copy 的循环中所示。

为了在每次模拟中将整行的值分配给同一个数组,您可以使用所谓的锯齿状数组(又名数组数组)。将数组行视为容纳另一个数组的容器。

只需三个步骤即可获得您想要的:

  • [0]。只需构建一个 1 维变体数组即可将 nSimulations 的数量保存为行数组(顺便说一句,我更喜欢这里基于 1 的数组计数)
  • [1]。通过myArray(iSim) = Range("QRA_Output_Copy").ValueQRA_Output_Copy的每一行结果分配给一个新的模拟行。
  • [2]。此外,Index() 函数允许通过Application.Index(myArray, 0, 0) 将结果一次性写入给定的目标单元格。

修改后的代码

Sub JaggedArray()
    Dim t As Double: t = Timer
    'Assign Values
    Dim nSimulations      As Long
    nSimulations = Range("QRA_Simulations").Value ' fixed number of simulations e.g.10000
    
    Dim nOutput_Variables As Long
    ''nOutput_Variables = Range("QRA_Output_Copy").Column       ' //column number??
    nOutput_Variables = Range("QRA_Output_Copy").Columns.Count  ' better: columns.count
    '[0] Build jagged array (as array container)
    Dim myArray           As Variant
    ''ReDim myArray(1 To nSimulations, 1 To nOutput_Variables)  'dimension array to have #rows=simulations and #columns=output variables
    ReDim myArray(1 To nSimulations)                            '<< define "jagged" array
     
    'Run loop
    Dim iSim As Long
    For iSim = 1 To nSimulations
        'run simulation stuff etc.
        '...
        
        '[1] Store simulation results as a row in a 1-dim "jagged" array
        Dim out: out = Range("QRA_Output_Copy").Value
        myArray(iSim) = out                                      '<< assign current row array

    Next iSim
    '[2] Write results all at once
    Range("Output").Resize(UBound(myArray), nOutput_Variables).Value = _
        Application.Index(myArray, 0, 0)
    Debug.Print "Needed " & Format(Timer - t, "0.00 secs")

End Sub

旁注:

上面的代码将整个数组写入一个目标。如果您愿意,但是要从 myArray 中获取单个项目,您必须按如下方式引用它:

    myArray(n)(i,j)

其中n 是模拟计数器,ij 是数组索引。当我将每一行作为数据字段数组(默认情况下基于 1 的 2-dim 数组)传递时,单个“行”索引 i 始终等于 1,j 指的是每个传递的一组中的“列”号行项目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    相关资源
    最近更新 更多