【问题标题】:What am I doing wrong? Removing duplicates using Excel VBA我究竟做错了什么?使用 Excel VBA 删除重复项
【发布时间】:2018-12-22 03:01:49
【问题描述】:

我是 VBA 新手,所以这可能是一个非常明显的错误。

为了简短起见,我尝试根据两个标准删除行:在 A 列中,如果它们具有相同的值(重复),在 B 列中,差异小于 100 ,然后从底部删除一行。

示例数据:

Column A  Column B          
1         300              
1         350     SHOULD be deleted as second column diff. is <100 compared to row above
2         500              
2         700     Should NOT be deleted as second column diff. is not <100

这是我想出的代码:

Sub deduplication()

Dim i As Long
Dim j As Long
Dim lrow As Long

Application.ScreenUpdating = False

With Worksheets("Sheet1")

lrow = .Range("A" & .Rows.Count).End(xlUp).Row

    For i = lrow To 2 Step -1
        For j = i To 2 Step -1
            If .Cells(i, "A").Value = .Cells(j, "A").Value And .Cells(i, "B").Value - .Cells(j, "B").Value < 100 Then
               .Cells(i, "A").EntireRow.Delete
            End If
        Next j
    Next i

End With

End Sub

这在很大程度上有效,但前提是第二个标准是大于 (>)而不是小于 (每一行。我究竟做错了什么?有简单的解决方法吗?

谢谢

【问题讨论】:

  • 需要取差值的绝对值吗?另外,用链式表达式检查括号。
  • 考虑使用辅助列,这将使 vba 代码更容易。示例 C 列(例如单元格 C3):=IF(AND(A2=A3, ABS(B3-B2)&gt;100),"Delete", "Keep")。然后您的 vba 代码可以简单地在 c 列上向后循环并删除那些具有“删除”的内容。我喜欢下面@urdearboy 的回答,但是对于更复杂的问题,使用辅助列是一种方便的技术。

标签: vba excel duplicates


【解决方案1】:

这样的东西应该适合你:

Sub tgr()

    Dim ws As Worksheet
    Dim rDel As Range
    Dim rData As Range
    Dim ACell As Range
    Dim hUnq As Object

    Set ws = ActiveWorkbook.Sheets("Sheet1")
    Set hUnq = CreateObject("Scripting.Dictionary")


    Set rData = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp))
    If rData.Row = 1 Then Exit Sub  'No data

    For Each ACell In rData.Cells
        If Not hUnq.Exists(ACell.Value) Then
            'New Unique ACell value
            hUnq.Add ACell.Value, ACell.Value
        Else
            'Duplicate ACell value
            If Abs(ws.Cells(ACell.Row, "B").Value - ws.Cells(ACell.Row - 1, "B").Value) < 100 Then
                If rDel Is Nothing Then Set rDel = ACell Else Set rDel = Union(rDel, ACell)
            End If
        End If
    Next ACell

    If Not rDel Is Nothing Then rDel.EntireRow.Delete

End Sub

【讨论】:

    【解决方案2】:

    没有

    If .Cells(i, "A").Value = .Cells(j, "A").Value And .Cells(i, "B").Value - .Cells(j, "B").Value < 100 Then
    

    在声明的第二部分,您只是将 .Cells(j, "B").Value 与 const 100 进行比较!

    但是

    If .Cells(i, "A").Value = .Cells(j, "A").Value And Abs(.Cells(i, "B").Value - .Cells(j, "B").Value) < 100 Then
    

    Abs() 可能会有所帮助,否则只保留 ( )

    【讨论】:

    • 我同意使用Abs(),否则比较有时会失败(即寻找大于 10 的差异:4-50&gt;10 将评估为 false 为 4-50 => - 45,小于 10)。但是,比较实际上是在那里做减法。
    • 回复有点晚,但谢谢,这是我遗漏的小事。
    【解决方案3】:

    自从您以j = i 开始以来,每个第一个 j 循环都通过将一行与其自身进行比较来开始。一个值和它自己的差总是为零。 (它还将第 2 行与自身进行比较作为最后一步。)

    但是,如果你切换:

    For i = lrow To 2 Step -1
    For j = i To 2 Step -1
    

    到:

    For i = lrow To 3 Step -1
    For j = i - 1 To 2 Step -1`
    

    代码将比较所有不同的行而不进行自我比较。

    另一点(@Proger_Cbsk 的answer 想到的)是,仅用减法.Cells(i, "B").Value - .Cells(j, "B").Value &lt; 100 进行比较有时会导致意外结果。

    例如,假设.Cells(i, "B").Value = 1.Cells(j, "B").Value = 250。我们可以通过查看来判断,至少有 100 的差异,所以你会期望这部分表达式的计算结果为 False。但是,通过直接替换,您会得到表达式:1 - 250 &lt; 100。自 1 - 250 = -249 和自 -249 &lt; 100 以来,表达式实际上将计算为 True。

    但是,如果您要将 .Cells(i, "B").Value - .Cells(j, "B").Value &lt; 100 更改为 Abs(.Cells(i, "B").Value - .Cells(j, "B").Value) &lt; 100,则表达式现在将查看 difference 是否大于或小于 100,而不是查看 >减法结果大于或小于100。

    【讨论】:

      【解决方案4】:

      坚持您的代码格式,您也可以使用一个For 循环来执行此操作。

      For i = lrow To 3 Step -1
          If .Cells(i, "A") = .Cells(i - 1, "A") And (.Cells(i, "B") - .Cells(i - 1, "B")) < 100 Then
              .Cells(i, "A").EntireRow.Delete
          End If
      Next i
      

      【讨论】:

        【解决方案5】:

        为什么不使用内置命令:

        Worksheets("Sheet1").Range("$A:$A").RemoveDuplicates Columns:=1, Header:=xlYes
        

        Range.RemoveDuplicates Method (Excel)

        【讨论】:

          猜你喜欢
          • 2015-12-02
          • 2013-08-06
          • 1970-01-01
          • 2015-09-15
          • 2016-07-18
          • 2019-12-23
          • 2014-06-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多