【问题标题】:Extremely slow VBA code when formatting cells格式化单元格时非常慢的 VBA 代码
【发布时间】:2014-09-26 07:54:44
【问题描述】:

尝试格式化工作簿中的 2 列时,宏的执行速度非常慢。要格式化大约 4000 行,需要 10 多分钟。

日期是从将它们存储为字符串的外部源填充的。

注释代码时,它会在 60 秒内加载。

代码

'Discover last row of data
    RowsToProcess = Range("A" & Rows.Count).End(xlUp).Row

    For i = 6 To RowsToProcess
    Worksheets("Data").Range("B" & i).Select
    Selection.NumberFormat = "dd/mm/yy;;"
    Selection.Value = CDate(Selection.Value)

    Worksheets("Data").Range("C" & i).Select
    Selection.NumberFormat = "dd/mm/yy;;"
    Selection.Value = CDate(Selection.Value)

    Next i

下面的代码也没有按要求的格式格式化单元格。

Worksheets("Data).Columns("C").NumberFormat = dd/mm/yy;;"

【问题讨论】:

  • 日期最初作为字符串加载到 col B 和 col C 时会是什么样子? “dd/mm/yy;;”,比如“03/08/14;;”?
  • @Dan Wagner - 它们以多种格式加载,例如2014 年 3 月 8 日,2014 年 7 月 3 日,2014 年 5 月 6 日(月/日/年)。
  • 酷——感谢您的澄清。另一个问题哈哈。您如何确保 mm/dd 与 dd/mm 之间的正确处理?例如,考虑05/06/2014,如上所述。您怎么知道该日期是 2014 年 5 月 6 日还是 2014 年 6 月 5 日?
  • 我猜测 dd/mm 格式的日期是不可能在美国语言环境中表示的日期,例如:2013 年 12 月 31 日等。这些将提供一些线索,表明数据的来源使用了另一个区域设置,并且应该假设 所有 日期相同的出处日期,即使它们 似乎 是正确的美国格式的日期,例如 01/02/2013(可能是 2 月 1 日,不是 1 月 2 日)。

标签: vba excel


【解决方案1】:

@aelgoa 链接到的帖子是正确的。当用于加速代码的标准 Application.ScreenUpdating 选项不够用时,我会转向 Variant 数组。

(如果您想了解我如何使用 Application.ScreenUpdating 等,包裹在 GoFast 函数中,请在此处查看我的答案:VBA code optimization

下面的脚本是这样工作的:

  1. 将 B 列和 C 列中定义的 Range 加载到 Variant 数组中
  2. 在那里应用CDate 逻辑(而不是每次都访问Sheet
  3. CDate-modified 数组写入Sheet

但有一个警告——我在上面的评论中关于区分 mm/dd 和 dd/mm 的问题(比如 2014 年 5 月 6 日与 2014 年 6 月 5 日)仍然存在。我将根据您的想法修改下面的代码。谢谢!

Option Explicit
Sub ProcessDates()

Dim AryColBandC As Variant
Dim DateFormatB As Date, DateFormatC As Date
Dim RngColBandC As Range
Dim LastRow As Long, Counter As Long
Dim MySheet As Worksheet

'set references up-front
Set MySheet = ThisWorkbook.Worksheets("Sheet1")
With MySheet
    LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
    Set RngColBandC = .Range(.Cells(6, 2), .Cells(LastRow, 3))
End With

'load the B-C column range into a variant array
AryColBandC = RngColBandC

'loop through the variant array, applying the date
'conversion to each entry in the array and writing back
For Counter = LBound(AryColBandC) To UBound(AryColBandC)
    DateFormatB = CDate(AryColBandC(Counter, 1)) '<~ temporarily store
    DateFormatC = CDate(AryColBandC(Counter, 2)) '<~ dates here

    AryColBandC(Counter, 1) = DateFormatB
    AryColBandC(Counter, 2) = DateFormatC
Next Counter

'write the results out to the sheet
For Counter = LBound(AryColBandC) To UBound(AryColBandC)
    MySheet.Cells(5 + Counter, 2) = AryColBandC(Counter, 1)
    MySheet.Cells(5 + Counter, 3) = AryColBandC(Counter, 2)
Next Counter

End Sub

【讨论】:

  • 谢谢丹。会试一试。假设日期列是连续的吗?如果日期存储在不同的列中,例如B、C、F、J 等?
  • 此设计确实假设您要转换的信息位于 B 列和 C 列中,但您可以通过调整 RngColBandC 的定义来调整它,或者,如有必要,添加新的 @ 987654334@ 变量来存储不是邻居的列。过程:(1) 将Range(s) into Variant Array(s), (2) Apply CDate` 逻辑加载到Variant Array(s),(3) 写入结果应该不会有太大变化。
  • -谢谢。我试了一下代码,它同样慢。它需要与原始代码一样长的时间。
  • 老实说,这是一个非常有趣的结果,我很乐意帮助您深入了解这个性能问题。 您是否介意发布您最初运行的完整脚本以及您运行的基于变体数组的代码,以查看是否有任何其他线索可以指出瓶颈? 有很多,这里还有更多有才华的开发人员——我相信他们也会有意见......
猜你喜欢
  • 1970-01-01
  • 2018-10-12
  • 1970-01-01
  • 2016-11-04
  • 1970-01-01
  • 2016-10-20
  • 2012-06-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多