【问题标题】:Stuck in loop while code has been properly executed代码已正确执行时陷入循环
【发布时间】:2020-01-30 13:14:03
【问题描述】:

如果满足特定条件(E 列),我编写了以下代码来清除重复数据集。它扫描 1216 行数据(LastRow 有 1216 个命中)并清除重复项。我遇到的唯一问题是,如果我有两三个重复项,它只会删除一个重复项。

我编写了另一行代码,说明如果多次找到单个项目(B 列),则名为 statement 的变量等于 TRUE。所以我希望循环继续,直到数据集中没有重复项,这也会将变量变为 FALSE 并停止循环。然而,循环无限地继续。当我手动停止脚本时,它似乎已经清除了所有重复项。

Sub ClearDataSet()

Dim LastRow As Integer
Dim i As Integer
Dim Rng, cell As Range
Dim Statement As Boolean

Set ws1 = ThisWorkbook.Worksheets("sheet1")

Set Rng = ws1.Range(("D1"), ws1.Range("D1").End(xlDown))
LastRow = Cells(Rows.Count, "A").End(xlUp).Row

ws1.Range("A1").CurrentRegion.Sort _
  key1:=ws1.Range("D1"), order1:=xlAscending, _
  Key2:=ws1.Range("E1"), order2:=xlAscending, Header:=xlYes

Do

    For i = 2 To LastRow

        If ws1.Cells(i, "D") = ws1.Cells(i + 1, "D") And _
          (ws1.Cells(i, "E") < ws1.Cells(i + 1, "E") Or _
          ws1.Cells(i, "E") = ws1.Cells(i + 1, "E")) Then

            Rows(i).Delete
        End If

   Next i

   For Each cell In Rng
       If WorksheetFunction.CountIf(Rng, cell.Value) > 1 Then
           Statement = True
       End If
   Next cell

Loop Until Statement <> True

End Sub

编辑:M Schalk 解决方案后调整(更高效)脚本

Sub ClearDataSet()

Dim LastRow As Integer
Dim i As Integer
Dim Rng, cell As Range
Dim Statement As Boolean

Dim StartTime As Long
Dim TimeElapsed As Long

StartTime = Timer

Set ws1 = ThisWorkbook.Worksheets("sheet1")

Set Rng = ws1.Range(("D1"), ws1.Range("D1").End(xlDown))
LastRow = Cells(Rows.Count, "A").End(xlUp).Row

ws1.Range("A1").CurrentRegion.Sort _
  key1:=ws1.Range("D1"), order1:=xlAscending, _
  Key2:=ws1.Range("E1"), order2:=xlAscending, Header:=xlYes

For i = 2 To LastRow

    If ws1.Cells(i, "D").Value = "" Then
        GoTo OverStepcode
    ElseIf _
      ws1.Cells(i, "D") = ws1.Cells(i + 1, "D") And _
      (ws1.Cells(i, "E") < ws1.Cells(i + 1, "E") Or _
      ws1.Cells(i, "E") = ws1.Cells(i + 1, "E")) Then

        Rows(i).Delete
        i = i - 1
    End If

Next i

OverStepcode:

TimeElapsed = Round(Timer - StartTime)
MsgBox "The code ran successfully in " & TimeElapsed & " seconds vbinformation"

End Sub

【问题讨论】:

  • 我为我的解决方案添加了一个更轻量级且易于阅读的解决方案,您应该尝试一下。

标签: excel vba loops


【解决方案1】:

在循环中没有将statement 设置为False。因此,循环结束条件永远不会满足。如果我正确理解您的目标,您应该在此处添加:

    If ws1.Cells(i, "D") = ws1.Cells(i + 1, "D") And _
        (ws1.Cells(i, "E") < ws1.Cells(i + 1, "E") Or ws1.Cells(i, "E") = ws1.Cells(i + 1, "E")) Then
         Rows(i).Delete
         statement = False
    End If

另外,Loop Until Statement &lt;&gt; TrueLoop Until Statement = False 相同,我觉得它更容易阅读。

另外,这似乎是一种过于复杂的方法,您是否尝试过使用Remove Duplicates

作为另一个更轻量级的解决方案,您可以删除整个 statement 并在找到重复项后简单地添加 i = i - 1。这可以确保您捕获相同值的多个重复项,并且您不需要整个 Do ... Loop 部分。试试这个修改后的版本。

For i = 2 To LastRow

    If ws1.Cells(i, "D") = ws1.Cells(i + 1, "D") And _
        (ws1.Cells(i, "E") < ws1.Cells(i + 1, "E") Or ws1.Cells(i, "E") = ws1.Cells(i + 1, "E")) Then
         Rows(i).Delete
         i = i - 1
    End If

Next i

【讨论】:

  • 谢谢,这似乎有效!我假设语句变量会自动变为 FALSE,因为它是一个布尔值。我什至测试了代码,它在我的本地人屏幕上显示为 FALSE。关于我复杂的方法。数据集包含不同合同的不同零件编号,合同结束日期不同。我不希望脚本只删除任何重复项,但删除日期最新的那个。在我看来,这似乎是最简单的方法,而且我还在学习如何正确编码;)
  • 啊,我明白了,您仍然应该尝试我添加到答案末尾的第二个解决方案。这应该可以实现您正在寻找的内容,同时更高效且更易于阅读。 :)
  • 谢谢,真是天才!应该想到这样的解决方案。我稍微调整了我的代码(请参阅我的原始帖子中的编辑)。 i = i - 1 行也使它陷入无限循环,尽管 LastRow 值保持为 1216 而 600 行被删除。所以它一直卡在最后一个非空行(575)。我添加了一行 GoTo 代码来绕过这个
  • 另外代码已在 6 秒内执行(1200 行)
  • 啊,你是对的。您也可以在.Delete 之后添加LastRow = LastRow - 1 以绕过此问题。将保持代码相对简单。
【解决方案2】:

我看到两件事:

首先:你做一个Do Until Statement&lt;&gt;True。但是在您的代码中,没有任何东西可以改变Statement 的值。在第一次运行代码时,当 VBA 第一次初始化 de 变量时,是的,默认值将是 False,但随后您的代码会更改此处的值:

If WorksheetFunction.CountIf(Rng, cell.Value) > 1 Then
    Statement = True
End IF

所以条件可能没有被满足。

建议:当您使用If ...then 时,如果只有一条语句并且没有Else 部分,您可以在一行中输入所有内容。这意味着您上面的代码可以像这样恢复:

If WorksheetFunction.CountIf(Rng, cell.Value) > 1 Then Statement = True

第二:这只是理论,我没有正确测试。

您的For Each,我认为它可能无法正常工作。你有这个:

For Each cell In Rng
    If WorksheetFunction.CountIf(Rng, cell.Value) > 1 Then
        Statement = True
    End If
Next cell

在上面的代码中,您正在循环rng. 中的 每个 单元格之前,您执行的是 Set Rng = ws1.Range(("D1"), ws1.Range("D1").End(xlDown))。但后来您删除了行,并且您从未更新过rng。这意味着,rng 中可能有几个空白值,因为您分配了 before 删除范围。

因为有几个空白值,WorksheetFunction.CountIf(Rng, cell.Value) 将返回总是大于 1,使Statement=True 并创建一个永恒的循环。

【讨论】:

  • 第二点是一个很好的观察,我什至没有想到这一点。但是,我刚刚对其进行了测试,如果单元格被删除,VBA 会自动调整Range,因此不会有问题。
  • 我也预料到了你描述的行为。
  • 感谢您对 foxfire 的评论,我在 m.schalk 他的评论之后调整了代码。它甚至不再包含设置的 Rng 行。
【解决方案3】:

问题可能出在:

For Each cell In Rng
    If WorksheetFunction.CountIf(Rng, cell.Value) > 1 Then
        Statement = True
    End If
Next cell

Statement 被设置为true,如果还有重复的话。它需要检查,如果没有剩余,然后将其设置为false

【讨论】:

  • 谢谢你,你之前的回答是一样的,我修好了。
猜你喜欢
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
  • 2016-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-21
相关资源
最近更新 更多