我有一张工作簿,其中包含两张我需要执行操作的数据。我开始直接从工作表中处理数据,但很快发现它非常慢,所以更改了将工作表读入两个数组(在两个单独的方法中调用Workbook_Open
)。
我为每张工作表上的数据创建了一个用户定义的类型,然后我发现我无法将这些添加到集合或脚本字典中,因此我将它们转移到了类中。
所以现在我有一个名为CDealerData
的类,每个类都有4个私有字段和公共属性。问题是,将数据读入数组的执行时间是我使用类型时的两倍。这就是它是怎么回事,或者我做错了什么。
类别:
Option Explicit
Private pBAC As String
Private pAccountNumber As String
Private pYear As Integer
Private pUnits As Variant
Public Property Get BAC() As String
BAC = pBAC
End Property
Public Property Let BAC(Value As String)
pBAC = Value
End Property
Public Property Get AccountNumber() As String
AccountNumber = pAccountNumber
End Property
Public Property Let AccountNumber(Value As String)
pAccountNumber = Value
End Property
Public Property Get Year() As String
Year = pYear
End Property
Public Property Let Year(Value As String)
pYear = Value
End Property
Public Property Get Units() As String
Units = pUnits
End Property
Public Property Let Units(Value As String)
pUnits = Value
End Property
Option Explicit
Private pBAC As String
Private pAccountNumber As String
Private pYear As Integer
Private pUnits As Variant
Public Property Get BAC() As String
BAC = pBAC
End Property
Public Property Let BAC(Value As String)
pBAC = Value
End Property
Public Property Get AccountNumber() As String
AccountNumber = pAccountNumber
End Property
Public Property Let AccountNumber(Value As String)
pAccountNumber = Value
End Property
Public Property Get Year() As String
Year = pYear
End Property
Public Property Let Year(Value As String)
pYear = Value
End Property
Public Property Get Units() As String
Units = pUnits
End Property
Public Property Let Units(Value As String)
pUnits = Value
End Property
模块:
Option Explicit
Public NumberOfYears As Integer
Public DealersData() As CDealerData
Public Sub ReadDealerData()
'** Reads the contents of RawData into an Array
'** of custom type DealerData, defined above
Dim MyDealerData As CDealerData
Dim LastRow As Long
Dim i As Long
Dim j As Long
LastRow = SheetRawData.UsedRange.Rows.Count
ReDim DealersData(LastRow * NumberOfYears)
For i = 0 To LastRow
For j = 0 To NumberOfYears - 1 'Year columns
Set MyDealerData = New CDealerData
MyDealerData.BAC = SheetRawData.Cells(i + 2, 1).Value
MyDealerData.AccountNumber = SheetRawData.Cells(i + 2, 3).Value
MyDealerData.Year = j + 1
MyDealerData.Units = CDec(SheetRawData.Cells(i + 2, 4 + j).Value) 'Assign column based on j
Set DealersData(i) = MyDealerData
Next j
Next i
End Sub
答案 0 :(得分:5)
由于种种原因,UDT比以这种方式使用类要快得多。
为了提高性能,您可以考虑使用公共变量而不是私有属性,但是这可能会失败使用类的目的。
此外,加快速度的一般方法是尽可能少地访问电子表格。
例如代码如下
For i = 1 to 10
Variable = Worksheets("Sheet1").Range("A1").Cell(i,1).Value
Next i
可以替换为
Dim VariantArray as Variant
VariantArray = Workeheets("Sheet1").Range("A1:A10")
' Now VariantArray(0,0) has the first element, (1,0) has the second, etc.
关于性能分析的说明:请注意@ BlackHawk在下面的评论中的建议,使用MicroTimer工具。它非常有用,可以隔离部分代码并将性能影响发现到非常精确的级别。
此外,虽然对于任何平台都是如此,但VBA性能有时可能会不一致,具体取决于Excel目前的资源压力,因此,即使MicroTimer精确,也可能无法准确代表您可能需要考虑在不同时间运行循环,以正确评估代码不同部分的影响。
答案 1 :(得分:1)
使用此语法通过一个操作Dim x() as Variant : x = Range("A1").Resize(40,20).Value
读取整个数组。
这将读取从A1
开始的40行和20列的单元格到Variant(,)
的2D数组。
你可以循环遍历这个数组,将值放入用户类型中,它会更快,比如DealersData(i*NumberOfYears+j).BAC = x(2*i-1,j)
,或者你的事情有条理。
答案 2 :(得分:0)
第一个我会优化CDealerData-Class,如下所示:
Private pUnits As Decimal 'instead of Variant, the internal mapping uses Time
Private pYear As Long 'instead of integer because outside of the Class you calc with Long
此外,我建议您创建一个方法来将数据设置为一行而不是可写属性:
Public Sub SetData(BAC As String, AccountNumber as String, Year as Long, Units as Decimal)
pBAC = BAC
pAccountNumber = AccountNumber
pYear = Year
pUnits = Units
End Sub
您的模块中的用法如下所示:
For i = 0 To LastRow
For j = 0 To NumberOfYears - 1 'Year columns
Set MyDealerData = New CDealerData
MyDealerData.SetData(SheetRawData.Cells(i + 2, 1).Value, SheetRawData.Cells(i + 2, 3).Value, j + 1, CDec(SheetRawData.Cells(i + 2, 4 + j).Value))
'Assign column based on j
Set DealersData(i) = MyDealerData
Next j
Next i
同样使用Class,您可以使用Collection,并且您不需要为阵列提供ReDim。
希望它有所帮助。
干杯 安迪