Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel 如何加快ListObject中的检查和复制_Excel - Fatal编程技术网

Excel 如何加快ListObject中的检查和复制

Excel 如何加快ListObject中的检查和复制,excel,Excel,我一直在处理一个项目,在这个项目中,如果添加了太多的数据行(在本例中是3000行),工作簿就会崩溃。 虽然我已经更新了工作簿,使它现在至少不会崩溃,但它的运行速度仍然非常慢——只需5列就可以添加900行,这大约需要33秒。结束表可能有大约35列(其中大约15列是公式)和5000多行,所以我已经担心了。同事们还希望能够使用“不匹配”表进行更新:Importable可能有A、B、C、E列,master将有A、C、E、F列,而实际需要的列(在adminTable中)是A、C、E列。 有人有什么想法吗?

我一直在处理一个项目,在这个项目中,如果添加了太多的数据行(在本例中是3000行),工作簿就会崩溃。 虽然我已经更新了工作簿,使它现在至少不会崩溃,但它的运行速度仍然非常慢——只需5列就可以添加900行,这大约需要33秒。结束表可能有大约35列(其中大约15列是公式)和5000多行,所以我已经担心了。同事们还希望能够使用“不匹配”表进行更新:Importable可能有A、B、C、E列,master将有A、C、E、F列,而实际需要的列(在adminTable中)是A、C、E列。 有人有什么想法吗?此sub已包装在另一个sub中,该sub可关闭屏幕更新、显示警报和计算。我猜打嗝是在复印线上

Sub detectChanges(adminTbl As ListObject, importTbl As ListObject, masterTbl As ListObject)

  Dim i                           As Long
  Dim j                           As Long
  Dim elements As Long
  Dim Header As Variant
  Dim foundHeader As Variant
  Dim cHead As String
  Dim ID As Variant
  Dim foundID As Range

  elements = 0

  'loops through the set admin headers. This format will not copy non-similar data, nor overwrite custom columns that have been added to the data
 'NOTE: Below assumed that unique identifier is ALWAYS in first column.
  For i = 1 To masterTbl.ListRows.Count
    'grabs ID
    ID = masterTbl.ListColumns(1).DataBodyRange(i)
    'tests for a ID match
    Set foundID = importTbl.ListColumns(1).Range.Find(IC, LookAt:=xlWhole)

    If Not foundID Is Nothing Then
        'only checks for changes in admin columns, skipping the ID column
        For j = 2 To adminTbl.ListColumns.Count
            cHead = adminTbl.ListColumns(j).Name
            If masterTbl.ListColumns(cHead).DataBodyRange(i) <> 
            importTbl.ListColumns(cHead).DataBodyRange(foundID.Row - importTbl.HeaderRowRange.Row) Then
            'This line changes the color of the changed element

                    importTbl.ListColumns(cHead).DataBodyRange(foundID.Row - importTbl.HeaderRowRange.Row).Copy masterTbl.ListColumns(cHead).DataBodyRange(i)
                    masterTbl.ListColumns(cHead).DataBodyRange(i).Interior.Color = RGB(255, 235, 156)
                              'keeping track of elements
                    elements = elements + 1
            End If
        Next j

    End If

Next i

  'Say elements changed
 'MsgBox "Total elements changed in update: " & elements

End Sub
子检测更改(adminTbl作为ListObject,importTbl作为ListObject,masterTbl作为ListObject)
我想我会坚持多久
Dim j尽可能长
暗元素一样长
变光表头
将标题作为变体
作为字符串的Dim cHead
Dim-ID作为变量
作为射程
元素=0
'循环设置管理标题。此格式不会复制不相似的数据,也不会覆盖已添加到数据中的自定义列
'注意:下面假定唯一标识符始终位于第一列中。
对于i=1到masterTbl.ListRows.Count
“抢身份证
ID=masterTbl.ListColumns(1.DataBodyRange(i)
'测试ID匹配
Set foundID=importTbl.ListColumns(1).Range.Find(IC,LookAt:=xlother)
如果没有foundID,那么什么都不是
'仅检查管理列中的更改,跳过ID列
对于j=2到adminTbl.ListColumns.Count
cHead=adminTbl.ListColumns(j).Name
If masterTbl.ListColumns(cHead.DataBodyRange)(i)
然后
'此行更改更改的元素的颜色
importTbl.ListColumns(cHead).DataBodyRange(foundID.Row-importTbl.headerrorrange.Row).复制masterTbl.ListColumns(cHead).DataBodyRange(i)
masterTbl.ListColumns(cHead.DataBodyRange(i).Interior.Color=RGB(255235156)
"追踪要素",
元素=元素+1
如果结束
下一个j
如果结束
接下来我
”他说
“MsgBox”更新中更改的元素总数:“&elements”
端接头

提高性能的一种方法是减少VBA与Excel对象的交互,因此循环会对性能产生很大影响

让我们看看你的三个循环

循环1

i=1到masterTbl.ListRows.Count的

这是算法中的主循环,它可能在错误的表中循环。我觉得两张桌子都一样大,那就没关系了;但是,如果主控形状大于导入形状(通常情况下),则在主控形状中不可能存在于导入形状上的行之间进行不必要的循环

循环2

importTbl.ListColumns(1).Range.Find(IC,LookAt:=xlother)

许多人忽略了一个简单的事实,
Find
是一个循环,当嵌套在
For
循环中时,它的效率特别低。考虑循环的<代码>,该循环遍历500行的表:<代码>查找< /C> >将被调用500次,并对第一行进行500次的评估。如果所有500行都包含匹配项,则
Find
只需进行125250次求值即可找到所有500行。现在抓住你的座位,如果只有一个匹配项,并且它在第500排,
Find
将进行249499次评估,然后在249500排找到它。如果没有火柴呢?所有500行将被评估500次,惊人的250000次评估!不要忘记,这些都是对工作表的评估,这正是您希望最小化的

循环3

j=2到adminTbl.ListColumns.Count的

这是最内部的循环,负责执行实际工作。这里有几个问题,我将分别讨论

  • 如果
    headerrorwrange
    在运行时不会更改,则可以避免重复引用
    importTbl.headerrorwrange.Row
    ,并通过将行号分配给循环上方的变量来加快速度(尽管是不可接受的)。然后,您可以在任何需要的地方使用该变量

  • 一个细胞一个细胞的工作也在减慢速度。您必须一次读取一个单元格,但不必读取每个单元格。查找一个更改就足以使用
的退出更新循环中的表行


这是一个涉及大量重写代码的漫无边际的过程,但这不是我真正要做的。我会使用一个过滤器来减少外部循环的大小,并消除
Find
,从而获得低垂的果实

我们需要一个过滤器数组。这个非常快速的短循环很好:

Dim aryID() as String
ReDim aryID(1 to masterTbl.ListRows.Count)
For i = 1 To UBound(aryID)
    'grabs ID
    aryID(I) = masterTbl.ListColumns(1).DataBodyRange(i).Value2
Next i
我们需要分配过滤器,我们可以用一个线性滤波器来完成,因为当前的过滤器可能是活动的、非活动的或不存在的,所以过滤器可能很棘手。因此,在设置标准之前,我通常将表传递给sub,以将过滤器重置为已知状态:

ResetTableFilters masterTbl
masterTbl.Range.AutoFilter Field:=1, Criteria1:=arryID Operator:=xlFilterValues
理论上,您应该能够将其复制并粘贴到当前模块中并运行它。但这是写在手机上的,还没有经过测试


子ResetTableFilters(lo作为ListObject)
如果为lo.ShowAutoFilter,则为lo.DataBodyRange.AutoFilter
lo.DataBodyRange.AutoFilter
端接头
子检测更改(adminTbl作为ListObject,importTbl作为ListObject,masterTbl作为ListObject)
我像我一样暗淡
Sub ResetTableFilters(lo As ListObject)
    If lo.ShowAutoFilter Then lo.DataBodyRange.AutoFilter
    lo.DataBodyRange.AutoFilter                 
End Sub




Sub detectChanges(adminTbl As ListObject, importTbl As ListObject, masterTbl As ListObject)

Dim i As Long
Dim j As Long
Dim elements As Long
Dim Header As Variant
Dim foundHeader As Variant
Dim cHead As String
Dim ID As Variant
Dim foundID As Range

 elements = 0

 'loops through the set admin headers. This format will not copy non-similar data, nor overwrite custom columns that have been added to the data
 'NOTE: Below assumed that unique identifier is ALWAYS in first column.

Dim aryID() as String
ReDim aryID(1 to masterTbl.ListRows.Count)
For i = 1 To UBound(aryID)
    'grabs ID
    aryID(I) = masterTbl.ListColumns(1).DataBodyRange(i).Value2
Next i


For i = 1 To masterTbl.ListColumns(1).DataBodyRange(i).SpecialCells(xlCellTypeVisible).Count

    'checks for changes in admin columns, skipping the ID column
    For j = 2 To adminTbl.ListColumns.Count
        cHead = adminTbl.ListColumns(j).Name
        If masterTbl.ListColumns(cHead).DataBodyRange(i) <> 
        importTbl.ListColumns(cHead).DataBodyRange(foundID.Row - importTbl.HeaderRowRange.Row) Then
        'This line changes the color of the changed element


          importTbl.ListColumns(cHead).DataBodyRange(foundID.Row -   importTbl.HeaderRowRange.Row).Copy    masterTbl.ListColumns(cHead).DataBodyRange(i)

              masterTbl.ListColumns(cHead).DataBodyRange(i).Interior.Color = RGB(255, 235, 156)
                          'keeping track of elements
                elements = elements + 1
        End If
    Next j

End If

Next i

'Say elements changed
MsgBox "Total elements changed in update: " & elements

End Sub