VBA:大数据和数组的使用

时间:2018-04-26 09:31:50

标签: vba excel-vba excel

所以我正在使用大型28,000行加数据+。另外还可能有5个其他电子表格用于交叉引用。

我一直被告知阵列速度更快但是可以向我解释它似乎更快,你可以一次读取和写入大块数据到阵列中。在哪些方面我可以理解哪里可能会减少速度开销。

或者说Arrays比说起来更快......

Worksheet.range("A1").Value=AOtherWorksheet.range("A1").Value

如果情况如此,那么看起来有些神奇,可以解释为什么读取变体块会更快,但不一定能解释为什么将片材读入数组然后将数组放入第二张表格会更快。我是否误解了我只是试图取笑那个具体的部分。

欢迎大型电子表格自动化的任何其他技巧评论,但主要集中在理解这个标题。

1 个答案:

答案 0 :(得分:2)

我认为魔法是由复杂性引起的 - 每个细胞带有很多"行李"

其环境的数百个设置,大部分是关于单元格格式

  • HeightWidthRowHeightColumnWidthColumnRowFontIndentLevel等等

要查看所有属性,请观察Sheet1.Range("A1")

的观察窗口

(旁边有+的属性是具有各自属性集的复杂对象)

RangeProperties

使用数组进行优化的主要原因是避免所有格式化

每个小区"知道"关于所有设置,无论它们是否被更改,并且承载所有这些" weight"周围。大多数用户,大多数时候只关心单元格中的值,从不触摸格式。在极少数情况下,如果您需要修改每个单独的单元格.Borders.Interior.Color.Font等,您可能会被困在范围对象中,即便如此,是类似格式化单元格的分组和一次修改整个组的属性的方法

继续进行行李类比(这有点拉伸):在机场,如果我需要为乘客补充一支笔" John Doe"从他已经在飞机上的行李,在机场后面的杂物间,我将能够做到(我有我需要的所有信息),但它会花时间来回走动,拿着那个行李。对于一位乘客来说,它可以在合理的时间内完成,但需要多长时间才能重新装满20K笔,即100K或100万? (ONE - BY - ONE)

我以同样的方式查看Range <-> VBA互动:当时使用一个单独的单元格,就像携带每个行李一百万乘客一样,到杂物间在机场后面。这就是本声明的作用:

Sheet1.Range("A1:A1048576").Value = Sheet2.Range("A1:A1048576").Value

而不是从所有手提箱中提取所有笔,重新填充它们并将它们全部放回去

将范围对象复制到数组是隔离每个单元格的一个属性 - 其 Value (&#34;笔&#34;),来自所有其他设置(Excel对此非常有效)。我们现在只有一个数组的数组,没有其他格式设置。在内存中单独修改每个值,然后将它们全部放回到范围对象中:

Dim arr as Variant

arr = Sheet2.Range("A1:A1048576")    'Get all values from Sheet2 into Sheet1

Sheet1.Range("A1:A1048576") = arr

这也是复制/粘贴参数不同的地方:

Sheet2.Range("A1:A1048576").Copy

Sheet1.Range("A1:A1048576").PasteSpecial xlPasteAll

Timers for Rows: 1,048,573

 xlPasteAll                          - Time: 0.629 sec; (all values + all formatting)
 xlPasteAllExceptBorders             - Time: 0.791 sec
 xlPasteAllMergingConditionalFormats - Time: 0.782 sec; (no merged cells)
 xlPasteAllUsingSourceTheme          - Time: 0.791 sec
 xlPasteColumnWidths                 - Time: 0.004 sec
 xlPasteComments                     - Time: 0.000 sec; (comments test is too slow)
 xlPasteFormats                      - Time: 0.497 sec; (format only, no values, no brdrs)
 xlPasteFormulas                     - Time: 0.718 sec
 xlPasteFormulasAndNumberFormats     - Time: 0.775 sec
 xlPasteValidation                   - Time: 0.000 sec
 xlPasteValues                       - Time: 0.770 sec; (conversion from formula to val)
 xlPasteValuesAndNumberFormats       - Time: 0.634 sec

除数组之外的另一个方面是数据结构的索引类型

对于大多数情况,数组是可以接受的,但是当需要更好的性能时,有DictionaryCollection个对象

  • 一个阵列效率低下的是找到我们需要遍历每个元素的元素

  • 更方便的选择是访问特定项目,速度更快

Dim d As Object                               'Not indexed (similar to linked lists)
Set d = CreateObject("Scripting.Dictionary")  'Native to VB Script, not VBA

d.Add Key:="John Doe", Item:="31"             'John Doe - 31 (age); index is based on Key
d.Add Key:="Jane Doe", Item:="33"
Debug.Print d("Jane Doe")                     'Prints 33

字典也有非常实用且快速的方法来检查项d.Exists("John Doe"),它会返回TrueFalse而不会出错(但收藏品不会出现)。使用数组,您必须遍历所有项目才能找到

我认为为大型列提取唯一值的最快方法之一是组合数组和字典

Public Sub ShowUniques()
    With Sheet1.UsedRange
        GetUniques .Columns("A"), .Columns("B")
    End With
End Sub

Public Sub GetUniques(ByRef dupesCol As Range, uniquesCol As Range)
    Dim arr As Variant, d As Dictionary, i As Long, itm As Variant

    arr = dupesCol

    Set d = CreateObject("Scripting.Dictionary")
    For i = 1 To UBound(arr)
        d(arr(i, 1)) = 0    'Shortcut to add new items to dictionary, ignoring dupes
    Next

    uniquesCol.Resize(d.Count) = Application.Transpose(d.Keys)

    'Or - Place d itms in new array (resized accordingly), and place array back on Range
    '    ReDim arr(1 To d.Count, 1 To 1)
    '    i = 1
    '    For Each itm In d
    '        arr(i, 1) = itm
    '        i = i + 1
    '    Next
    '    uniquesCol.Resize(d.Count) = arr
End Sub
From:   Col A    To: Col B
          1            1
          2            2
          1            3
          3
  • 字典不接受重复的密钥,只是忽略它们