【问题标题】:Looping through non-contiguous rows selected with a criteria循环遍历使用条件选择的非连续行
【发布时间】:2017-09-26 12:09:53
【问题描述】:

这是我在 SO 中的第一篇文章。如您所知,我不是专业的程序员,只是一个普通的上班族,不时做一些 VBA 以更快地完成他的工作。

我想使用 VBA 循环遍历一系列单元格,其中一个列中包含特定的标志值。这些范围是不连续的,因为我们选择具有连续标志值的范围,并且该值在每一行中随机变化。

例如在下表中,我们如何循环三次(因为有三个连续的 -1 标志的不连续范围)在第一次迭代中选择前三行,在第二次运行中选择第 5 行和第 6 行,并在第三次迭代中选择第 8 行?

+-------+---------+------+
| Index |  Value  | Flag |
+-------+---------+------+
|     1 | 0.43534 |   -1 |
|     2 | 0.24366 |   -1 |
|     3 | 0.23654 |   -1 |
|     4 | 0.56854 |    0 |
|     5 | 0.97867 |   -1 |
|     6 | 0.35678 |   -1 |
|     7 | 0.47845 |    0 |
|     8 | 0.74567 |   -1 |
+-------+---------+------+

【问题讨论】:

  • 无论是低层还是高层,一切都在循环。即使在数据库中,每条记录都有初始循环。关键是你如何处理循环,你能否在一个循环中完成你需要做的所有事情,而不需要重新循环。如果要对循环内的组执行计算,请考虑Do Loop While
  • 感谢@MacroMarc 的建议。您能否分享一些网络资源或关键字,我可以在其中阅读更多关于循环的信息,在它处于更高或更低级别的情况下,特别是在我应该如何处理循环算法以在单个循环中完成所有事情?抱歉,这是一个基本的计算机科学问题,因为我仍在努力学习该主题。

标签: vba excel


【解决方案1】:

以下代码将在消息框中给出结果,用Flag = -1 指定所有范围。根据您的示例数据图像,输出将为$C$2:$C$4$C$6:$C$7$C$9

Sub Demo()
    Dim ws As Worksheet
    Dim cel As Range, rng As Range, fCell As Range, tempRng As Range
    Dim lastRow As Long
    Dim isNegative As Boolean

    Set ws = ThisWorkbook.Sheets("Sheet2")      'change Sheet2 to your data sheet
    isNegative = False

    With ws
        lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row    'last row with data in Column C

        For Each cel In .Range("C2:C" & lastRow + 1)  'loop through each cell in Column C
            If cel.Value = -1 Then      'check if value is -1
                If Not isNegative Then
                    Set fCell = cel
                    isNegative = True
                End If
            Else                        'if not then set range
                If isNegative Then
                    If rng Is Nothing Then
                        Set rng = .Range(fCell, cel.Offset(-1, 0).Address)
                    Else
                        Set rng = Union(rng, .Range(fCell, cel.Offset(-1, 0).Address))
                    End If
                    isNegative = False
                End If
            End If
        Next cel
    End With
    For Each tempRng In rng.Areas 'loop through all ranges with -1
        MsgBox tempRng.Address
        'write your code here
    Next tempRng
End Sub

这里是对代码中使用的布尔变量isNegative 的简要说明。

isNegative 用于维护标志.Range("C2:C" & lastRow + 1) 中的最后一个单元格值是否为-1,并在开头设置为FALSE。当第一个-1 被反击时,isNegative 被设置为TRUE 并且fCell 被分配相应的单元格地址。直到循环遇到-1isNegative 将保持TRUE。当遇到值不等于-1 的单元格时,如果只遇到一个带有-1 的单元格,则使用rngfCell 到当前单元格使用Set rng = .Range(fCell, cel.Offset(-1, 0).Address) 设置范围,否则使用Set rng = Union(rng, .Range(fCell, cel.Offset(-1, 0).Address)) 如果超过一个遇到带有-1 的单元格。
当遇到第二个或更多连续单元格的值不等于-1 时,什么也不会发生。当遇到下一个值为-1 的单元格时,重复上述过程。

【讨论】:

  • Mrig,非常感谢您提供如此详细的答案,我没有意识到这个问题会在几个小时内得到解决。 SO 确实令人惊叹,其才华横溢的社区愿意帮助其他刚接触编程的人。
  • 如果您还有时间,我想问一下您是如何找到解决方案的?不一定是详细的解释,也许只是一个粗略的逻辑图,可以显示数据流并指导我更深入地挖掘和研究使用的方法。 (我对isNegativeisRange布尔变量的使用特别困惑)
  • @EmmanD。 - 我为isNegative 添加了解释。 isRange 不是必需的,将其用于测试并在上传答案时忘记将其从代码中删除。如果还有什么不清楚的,请告诉我。
  • 感谢您的详细解释!现在一切都清楚了。
【解决方案2】:

您仍然可以正常循环,但使用 If 语句检查第 3 列 (C) 是否有 -1,例如:

Dim i as Long

For i = 2 to 9 'Assumes 1 is a header row, despite 1-8 being counted
    If Cells(i,3).Value= -1 Then
        'Do something
    End If
Next i

【讨论】:

    【解决方案3】:

    我会考虑使用do while flag=-1 之类的东西。

    或者改为使用条件if Flag(index)=Flag(index+1) then *do something*,因为我认为更复杂的事情需要设计一个模块类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-06
      • 1970-01-01
      • 1970-01-01
      • 2015-12-01
      • 2017-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多