【问题标题】:Column comparison error in VBAVBA中的列比较错误
【发布时间】:2017-01-19 18:04:15
【问题描述】:

您好,我正在编写一个宏,用于比较 Excel 中不同工作表上的两列。 宏如下:

Sub Main()
Application.ScreenUpdating = False

    Dim stNow As Date
    stNow = Now

    Dim arr As Variant
    arr = Worksheets("Sheet2").Range("W3:W" & Range("W" & Rows.Count).End(xlUp).Row).Value

    Dim varr As Variant
    varr = Worksheets("Sheet3").Range("P3:P" & Range("P" & Rows.Count).End(xlUp).Row).Value

    Dim x, y, match As Boolean
    For Each x In arr
        match = False
        For Each y In varr
            If x = y Then match = True
        Next y
        If Not match Then
            Worksheets("Sheet1").Range("L" & Range("L" & Rows.Count).End(xlUp).Row + 1) = x
        End If
    Next

    Debug.Print DateDiff("s", stNow, Now)
Application.ScreenUpdating = True
End Sub

如果列在同一张纸上并且代码中没有图纸引用,则它可以完美运行。但现在它只复制 Sheet3 列 W 中的第一个单元格,尽管该值已经存在于 Sheet3 的 P 列中。

【问题讨论】:

  • 找到匹配时需要退出内循环。因此,将您的 if 更改为:If x = y Then : match = True : Exit For : End If 其中: 是新行。
  • @ScottCraner - 我认为你的评论应该是“你应该退出......”,而不是“你需要退出......”。如果没有Exit For,代码仍然可以工作,只是效率不高。
  • 不,如果没有退出匹配,将始终将 x 与数组中最后一个 y 的比较返回给 if 语句。 @YowE3K
  • @ScottCraner - 你病了 - Shai 累了 - 我厌倦了上班。
  • 高度建议看看@ShaiRado 的回答。这是一个很好的答案,可以帮助你在这么短的宏中学到很多东西。使用Match() 对代码的大小和速度有很大好处。如果您愿意,甚至可以标记为答案。至于其他人,去上班睡觉吧!耶!

标签: vba excel


【解决方案1】:

如您所见,当没有工作表引用时,它可以正常工作。

您需要始终限定Range()Rows.Columns.,否则它将使用ActiveSheet 是什么。

以下内容应该适合您。

Sub Main()
Application.ScreenUpdating = False

Dim stNow   As Date
stNow = Now

Dim arr     As Variant
With Worksheets("Sheet2")
    arr = .Range("W3:W" & .Range("W" & .Rows.Count).End(xlUp).Row).Value
End With

Dim varr    As Variant
With Worksheets("Sheet3")
    varr = .Range("P3:P" & .Range("P" & .Rows.Count).End(xlUp).Row).Value
End With

Dim x, y, match As Boolean
For Each x In arr
    match = False
    For Each y In varr
        If x = y Then
            match = True
            Exit For
        End If
    Next y
    If Not match Then
        With Worksheets("Sheet1")
            .Range("L" & .Range("L" & .Rows.Count).End(xlUp).Row + 1) = x
        End With
    End If
Next

Debug.Print DateDiff("s", stNow, Now)
Application.ScreenUpdating = True
End Sub

注意:我添加了With 语句以减少使用Worksheets("Sheetx"). 的重复性,此外,根据@ScottCraner 的评论更新了If x = y 语句。

我还看到您有一些未声明的变量。我建议将Option Explicit 添加到最开始(Sub Main() 之前)并声明所有变量。

【讨论】:

  • 为什么不使用Application.Match 剪切第二个For 循环搜索第二个数组中的所有元素,这样会节省很多代码运行时间
  • @ShaiRado - 好点。我只是按照 OP 的方式修复了代码,但我建议他们调查一下。另外,就个人而言,我会回避使用match 作为变量名,可能会使用isMatch 或其他名称。
【解决方案2】:

按照@BruceWayne 的回答,您可以替换代码的中间部分,而不是使用 2 x For 循环扫描每个数组内的所有元素,您只能有 1 个 @987654322 @循环,另一个将使用Application.Match函数来查找数组之间的匹配。

这应该会在比较大尺寸数组时为您节省大量代码运行时间。

注意:我已将您的 match 变量替换为 isMatchmatch 不是变量的最佳名称(因为有同名的函数)

编辑 1:删除了 isMatch 变量,因为它不需要。

子代码

Dim x
For Each x In arr
    If IsError(Application.Match(x, varr, 0)) Then '<-- no match between elements inside arrays
        With Worksheets("Sheet1")
            .Range("L" & .Range("L" & .Rows.Count).End(xlUp).Row + 1) = x
        End With
    Else '<-- there is a match between arrays
        ' do nothing , raise a "MsgBox"
    End If       
Next x

【讨论】:

  • 当然,您可以通过将If Not isMatch Then ... End If 块的内容放在isMatch = False 当前所在的位置来完全摆脱isMatch。跨度>
  • 你说得对,我每天工作 12 小时后,没有优化
  • 我刚开始我的 12 小时工作,所以我精神焕发,迫不及待!
  • @YowE3K 删除了 isMatch ,现在我睡了一夜好觉 :)
  • 我即将上交过夜!虽然不容易入睡 - 还是太热了 :( 但希望我们很快就会迎来一阵凉爽的南风。:)
猜你喜欢
  • 2013-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多