【问题标题】:Removing data from one sheet that appears in another using VBA使用 VBA 从一个工作表中删除出现在另一个工作表中的数据
【发布时间】:2015-05-12 08:52:12
【问题描述】:

我有 2 张纸,每张都有一张桌子。一个包含原始数据(2000 多行),一个包含我想从原始数据中删除的数据(500 行左右)。我有以下代码来执行此操作,但是它相当慢,我相信它可以更快:

Dim r As Range
Dim wsOriginal As Worksheet, wsDelete As Worksheet
Dim str As String
Dim i as Long
Set wsOriginal = ThisWorkbook.Sheets("List")
Set wsDelete = ThisWorkbook.Sheets("PermaDelete")

For i = wsDelete.UsedRange.Rows.Count To 2 Step -1
    str = wsDelete.Cells(i, 1).Value & wsDelete.Cells(i, 2).Value & wsDelete.Cells(i, 3).Value & wsDelete.Cells(i, 4).Value & wsDelete.Cells(i, 5).Value
    Set r = wsOriginal.Columns(30).Find(str, , xlValues, xlWhole, xlByRows, xlNext) ' Column 30 on original has concatenation of the required 5 rows, to match form of str
    If Not r Is Nothing Then
        Do
            wsOriginal.Rows(r.Row).EntireRow.Delete
            Set r = wsOriginal.Columns(30).Find(str, , xlValues, xlWhole, xlByRows, xlNext)
        Loop Until r Is Nothing
    End If
Next i

所以我遍历wsDelete 中的每一行并使用.Find 在较大的wsOriginal 中查找一行。如果找到它,则将其删除并再次查找同一行(因为一些确实在超过 1 行中复制了此信息)。对我来说,这听起来像是更快的方法(而不是循环通过wsOriginal),但代码本身似乎需要相当长的时间(2-3 分钟)。我正在使用.ScreenUpdating.EnableEvents 的常用技巧也设置为false。

我还能如何优化它以减少等待时间?

【问题讨论】:

  • 如果工作表 wsOriginal 有公式,那么它会在每次删除事件后重新计算它们。执行 Application.Calculation = xlManual 以停止重新计算。
  • 啊,是的。没想到。可以节省相当多的时间。稍后会尝试并报告。
  • 是的,切换到手动计算将其缩短到不到一分钟。将尝试以某种方式调整下面提到的Union 想法,看看我是否可以让它发挥作用以获得额外的提升。

标签: vba excel


【解决方案1】:

我最近在这里回复了一个类似的帖子:Need suggestions on how to speed up this bit of code [duplicate]

这个在循环之前:

Dim rng As Range
Set rng = Nothing

在循环而不是行删除中这样做:

If rng is Nothing Then
  rng =  wsOriginal.Cells(r.Row, 1)
Else
  rng = Union(rng,  wsOriginal.Cells(r.Row, 1))
End If

然后在循环结束后:

rng.EntireRow.Delete

编辑 修正了上面的错字,抱歉,绕过.Find 位: 在您执行set r 之后添加一行:firstAddress = r.Address 并将Loop Until 更改为Loop While Not r Is Nothing And r.Address <> firstAddress 这在这里得到了很好的解释:Range.Find Method (Excel)

【讨论】:

  • 不错的答案,但这对重复项不太适用,因为.Find 方法将始终返回该行,因此Loop Until r Is Nothing 行将永远不会完成。此外,代码应为If rng Is Nothing 而不是If rng = Nothing
  • 已将其调整为现在使用.FindNext(我发现它的命中率和失误率更高)现在使用这种方法工作(同时也让它存储原始地址。但是时间与原始代码相比,现在的差异可以忽略不计(时间减少 2 秒 - 基于 2 次运行减少 55 秒到 53 秒),因此将恢复到原始版本。认为这是重复检查,这意味着它不如 if 有效您使用的列表没有重复。
  • 奇怪的是速度差异并不明显 - 一次删除复杂范围通常比一次删除一行要快得多.. P.S.我已经为.Find 编辑了我的原始帖子。
  • 通常我会同意,但认为大部分时间可能都花在了 .Find 方法本身而不是删除行上(特别是如果 .Calculation 被关闭,这就是现在)。因为,从本质上讲,我在 2000 行中循环至少 500-600 次(wsDelete 中的每行至少两次),所以我认为删除在整体时间方面不会有太大作用。如果它是纯粹的删除,那么它可能会是一个更明显的百分比,因此更值得。
【解决方案2】:

有一个非常简单的解决方法。 Excel 的 REMOVE DUPLICATE 逻辑是删除出现在电子表格下方的重复项。

如果您想删除工作表 2 中出现在工作表 1 中的所有项目,只需将工作表 2 中的项目粘贴到工作表 1 的顶部,对该列运行 REMOVE DUPLICATE 函数,然后删除所有项目来自第 2 页。

就这么简单。

【讨论】:

  • 需要代码中的解决方案,因此要求代码优化而不是替代方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-12
  • 1970-01-01
  • 1970-01-01
  • 2019-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多