【问题标题】:VBA - Efficient for each loop for big rangesVBA - 对于大范围的每个循环都有效
【发布时间】:2021-07-01 16:44:28
【问题描述】:

我对 VBA 相当陌生,正在尝试找出如何在大范围 (500k) 中使用 for each 循环。

我想根据具有以下格式的概率计算表格中的几个场景:

Group Type   | Group 1 | Group 2 | Group 3.

Probability  | 20%     | 30%     | 70%

Scenario 1   | 0       | 1       | 0 

Scenario 2   | 0       | 0       | 1   
....

Scenario 500k| 0       | 1       | 1 

不幸的是,我的 For each 循环只能在高达 10k 的小范围内工作 - 你们中有人知道如何更好地使用它吗?

Sub ScenarioCalculation()
 
Dim propability As Double, random As Double, row As Long, col As Long

Application.ScreenUpdating = False

For col = 4 To 23
    For row = 25 To 100
        propability = Cells(12, col + 1).Value
        random = 0# + Rnd * 1#
        If random < propability Then
            Cells(row + 1, col + 1).Value = 1
            Else
            Cells(row + 1, col + 1).Value = 0
        End If
    Next row
Next col
 
End Sub

【问题讨论】:

  • 不要使用 Excel 超过 10k 行,它不是数据库。
  • 不是你使用的每个循环,为什么循环值在行 25 To 100 之间有上限?我不太了解您的真正问题(代码是否慢),即代码有什么问题?
  • 您似乎在给定范围内随机生成 0 和 1。如果是这样,您可以使用 excel 公式=RANDBETWEEN(0,1),它会随机给您零或一,然后将其复制到整个范围内,或者您可以使用 control+enter 一次在所有选定范围内输入公式。我认为循环遍历 vba 中的每个单元格会快得多。是的,但它是不稳定的,因此您必须将其复制为值。
  • @Naresh - 1 或 0 取决于第 12 行中单元格的值
  • @TimWilliams .. 我不确定。但我认为如果我们比较两个值;一个是已知的,另一个是随机的;那么一个比另一个多或少的概率也应该是 50%,比如 0 或 1。如果两个值都是未知的,那么它是 50%。我认为:)

标签: excel vba foreach


【解决方案1】:

逐个单元的操作相对较慢。您可以使用数组来提高性能。

这应该更快:

Sub ScenarioCalculation()
    
    Const NUM_SCENARIOS As Long = 10000 ' for example
    Dim propability As Double, random As Double, row As Long, col As Long, arr
    Dim rng As Range, ws As Worksheet
    
    Set ws = ActiveSheet 'for example
    
    Application.ScreenUpdating = False
    
    For col = 4 To 23
        propability = ws.Cells(12, col + 1).Value   'only need to read this once...
        Set rng = ws.Cells(25, col + 1).Resize(NUM_SCENARIOS)
        arr = rng.Value                             'create array from range
        'populate the array
        For row = 1 To UBound(arr, 1)
            random = 0# + Rnd * 1#
            arr(row, 1) = IIf(random < propability, 1, 0)
        Next row
        
        rng.Value = arr 'populate the range from the array
    Next col
 
End Sub

【讨论】:

  • 这比我的解决方案快得多,它也适用于大量行。 (刚刚测试过:1sec vs 50 secs for 100k)。学到了新东西
  • 即使是 500K 行也能更快地运行
【解决方案2】:

创建一个长变量并使用范围:

Dim i As Long
Dim rng As Range
Dim probability as variant
Dim col as integer

Set rng = Range("B2")


For col = 0 to 20
  probability=rng.offset(0,1).value
  For i = 1 To 500000
    random = 0# + Rnd * 1#
    rng.offset(0,2 + col).value = iif(random<probability,1,0)
    Set rng = rng.Offset(1, 0)
  Next
Next

通过这种方式,您可以使用 Excel 的内部功能来使用大量单元格并单独处理每一行。 正如@Tim Williams 所展示的那样:如果你把它括在一个

On Error Goto EndThisSub
  Application.ScreenUpdating = False
  ....
EndThisSub:
  Application.ScreenUpdating = True

它会更快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-10
    • 2013-01-21
    • 1970-01-01
    • 2015-06-01
    • 2015-10-04
    • 2018-11-11
    • 2020-08-08
    • 2018-02-13
    相关资源
    最近更新 更多