【问题标题】:Most Efficient Method for Removing Rows with Two Conditions两种条件下删除行的最有效方法
【发布时间】:2014-09-23 23:29:27
【问题描述】:

我要做的是删除电子表格中两个单独列中值为 0 的行,因为这表明该行中没有有用的数据。虽然可以将For loopIf/Then 条件一起使用,但我发现这非常慢,因为我的数据集有大约51,000 行,而且它实际上需要数小时甚至数天才能运行。

经过一番搜索,我发现了另一种方法,我认为它会更快并且目前正在使用:

Public Sub deleteRows()
     ' source: http://www.ozgrid.com/forum/showthread.php?t=64364
    Dim lastRow As Long
    Dim n As Long
    Dim RT As Date
    RT = Time

    With ActiveSheet
        lastRow = .Cells(.Rows.Count, 2).End(xlUp).Row
    End With

    For n = lastRow To 2 Step -1
        If (Trim(ActiveSheet.Cells(n, 3).Value) = 0) And (Trim(ActiveSheet.Cells(n, 6).Value) = 0) Then
            ActiveSheet.Cells(n, 1).EntireRow.Delete
        End If
    Next n
    MsgBox Format(Time - RT, "hh:mm:ss")
End Sub

但是,我只使用 1000 个单元进行了测试,运行时间为 402 秒,这表明以相同的速率运行所有数据需要 5.584 小时。

有什么方法可以加快这个过程吗?我错过了什么明显的东西吗?

*编辑:此代码作为另一个代码的子部分运行,其中 ScreenUpdating = False 在代码的开头声明。

【问题讨论】:

  • 如果您没有在代码的其他地方执行此操作,请在开始修改工作表之前关闭 ScreenUpdating。例如,将 Application.ScreenUpdating = False 放在 For 循环的前面。然后在 MsgBox 之前设置该值 = True
  • @andyholaday 我在代码的开头使用 Application.ScreenUpdating = False,我应该指定它。不过谢谢!

标签: excel performance vba loops


【解决方案1】:

不,实际上需要更长的时间。如果你删除一行,它下面的每一行都会单独上移,如果你要删除的行下面有更多行,这显然需要更长的时间。

这里有几个简单的方法:

  1. 使用 AutoFilter 过滤不需要的行,然后删除可见单元格。

  2. 使用自动筛选来筛选要保留的行并将其复制到新工作簿。

  3. 首先对值进行排序,以便所有不需要的行都位于底部。你已经从下往上删除了,所以你只需要在你的循环前面插入一个排序。

【讨论】:

  • 嗯,这确实回答了这个问题,但如果你提供了一个例子,那就太好了。因为我是自动过滤器的粉丝,所以我确实发布了一个使用它的方法。
  • @pnuts 抱歉不清楚...我在 stackoverflow 上的第一篇文章^^ Redshift 预测了将 1000 个单元格以线性方式循环到更大的工作表的执行时间,结果为 5.5 小时。由于执行时间将随着工作表变大而呈指数增长,因此需要更长的时间。因为您不仅必须删除更多行,而且删除每一行需要更长的时间,因为您必须移动更多行。好吧,要保留/删除的行将通过在第 3 列和第 6 列中过滤 value = 0 来隐式“选择”..不太确定这是否是您的意思
【解决方案2】:

这是一种使用自动过滤器的方法:

Public Sub deleteRows()
    Dim lastRow As Long
    Dim rng As Range
    Dim start

    start = Timer
    With ActiveSheet
        .AutoFilterMode = False
        lastRow = .Cells(.Rows.Count, 2).End(xlUp).Row
        '~~> Set the range of interest, no need to include the entire data range
        Set rng = .Range("B2:F" & lastRow)
        rng.AutoFilter 2, 0 '~~> filter zeros on C column
        rng.AutoFilter 5, 0 '~~> filter zeros on F column
        '~~> Delete the entire row of the remaining visible cells
        rng.Offset(1, 0).Resize(rng.Rows.Count - 1) _
            .SpecialCells(xlCellTypeVisible).EntireRow.Delete
        .AutoFilterMode = False
    End With
    Debug.Print (Timer - start) * 1000 '~~> in ms
End Sub

对样本数据进行了尝试和测试(单元格 B2:L52802)。
在我的机器上删除需要 11699.22 毫秒或大约 11.7 秒。
与您估计的 5 小时相比,我认为这已经足够快了(具体来说要快 1700 倍)。

【讨论】:

  • @pnuts 哇...你那里有什么机器!?顺便说一句,它与我猜的匹配数成正比。当我尝试它时,C 和 F 至少有 10k 匹配为零。所以这会给我留下 40k 左右的数据。当然,要删除的数据越多,Excel 处理的时间就越多。
  • @L42 我花了一点时间才让你的代码运行起来,但现在它看起来就像一个魅力。我不得不将 crireria 更改为 =“=0.000)”,但这似乎已经解决了所有问题。感谢您的帮助!
  • 还有一件事;仍然需要大约 55 秒才能按原样运行。但是,如果我删除代码的 EntireRow.Delete 部分中的 .Resize 和 .Offset 部分,它会在大约 12 秒内运行。这正常吗?
  • @Redshift 是的,你可以删除它。这是预期您有一个标题并调整大小以删除您已偏移的额外范围的旧习惯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多