为什么我的For ...每个声明都完整完整?

时间:2017-11-01 23:24:03

标签: excel-vba vba excel

当以下代码运行时,它不会完整地完成。我通常需要再运行几次以确保检查该范围内的所有数据,并在符合我的标准时删除该行。

Const A% = 1
Const B% = 2
Const C% = 3
Const D% = 4

'Some code

If myCL <> "" Then
    For Each Cell In RngB.Cells
        If Cell.Value <= myBal Then
            r = Cell.Row
            If ws.Cells(r, D) <= myScore And ws.Cells(r, C) Like myCL Then
                Cell.EntireRow.Delete
            End If
        End If
    Next Cell
ElseIf myCL = "" Then
    For Each Cell In RngB.Cells
        If Cell.Value <= myBal Then
            r = Cell.Row
            If ws.Cells(r, D) <= myScore Then
                Cell.EntireRow.Delete
            End If
        End If
    Next Cell
End If

我理解我在使用像For i = ## to 1 Step -1这样的东西时应该反过来循环一个范围,但我不相信这会适用于这种情况。

我的问题是,当Cell符合条件时,它有时会跳过它,然后重新运行代码,它将被删除。

3 个答案:

答案 0 :(得分:3)

另一种方法是,不是将行添加到数组中,或者向后循环并逐个删除行,而是将DelRng定义为Range对象。

每次都通过您的条件,而不是使用Row功能将DelRng添加到Union对象,最后,删除DelRng单触发。

<强>代码

Dim DelRng As Range  ' new range object, collects all rows that needs to be deleted

If myCL <> "" Then
    For Each Cell In RngB.Cells
        If Cell.Value <= myBal Then
            r = Cell.Row
            If ws.Cells(r, D) <= myScore And ws.Cells(r, C) Like myCL Then
                ' add current row to DelRng
                If Not DelRng Is Nothing Then
                    Set DelRng = Application.Union(DelRng, .Rows(r))
                Else
                    Set DelRng = .Rows(r)
                End If
            End If
        End If
    Next cell
ElseIf myCL = "" Then
    For Each Cell In RngB.Cells
        If Cell.Value <= myBal Then
            r = Cell.Row
            If ws.Cells(r, D) <= myScore Then
                ' add current row to DelRng
                If Not DelRng Is Nothing Then
                    Set DelRng = Application.Union(DelRng, .Rows(r))
                Else
                    Set DelRng = .Rows(r)
                End If
            End If
        End If
    Next cell
End If

' now delete the entire rows at once (will save you a lot of run-time)
If Not DelRng Is Nothing Then DelRng.Delete

答案 1 :(得分:1)

您通过删除正在迭代的行(For Each从左到右,从顶行到底行)扫描For Each语句下的地毯。 Excel非常适合在&#34; next&#34;恢复迭代。单元格,它确实位于刚刚删除的行之后的行上,通常位于右侧的1个单元格中。但是,您的代码错过了当前新行的所有最左侧单元格,其中一些可能符合您的标准。

修改

可以通过某种方式记下要删除的行,而不是在For Each循环中删除它们来规避该问题。我个人最喜欢的方法是使用Scripting.Dictionary,如下所示:

Sub ForEachWithRowDeleteDemo()
    Dim rangeOfInterest As Excel.Range
    Dim cell As Excel.Range
    Dim dicRowIndexesToDelete As Object 'Scripting.Dictionary
    Dim rowIndex As Variant

    Set rangeOfInterest = Sheet1.Range("A1:Z10") 'ASSUMPTION: rangeOfInterest is a contiguous range; no checks are made here.
    Set dicRowIndexesToDelete = CreateObject("Scripting.Dictionary")

    For Each cell In rangeOfInterest.Cells
        If cell.Value2 = 123 Then '...your conditions go here.
            'Cumulate distinct row indexes.
            dicRowIndexesToDelete(cell.Row - rangeOfInterest.Row + 1) = True
        End If
    Next

    If dicRowIndexesToDelete.Count > 0 Then
        If rangeOfInterest.Cells.Count = 1 Then
            'Exceptional case: rangeOfInterest is a single cell.
            rangeOfInterest.EntireRow.Delete
        Else
            'Mark each of the range's rows.
            rangeOfInterest.Clear
            For Each rowIndex In dicRowIndexesToDelete.Keys
                rangeOfInterest.Cells(rowIndex, 1) = True
            Next

            'Find the marks and delete the entire rows.
            rangeOfInterest.SpecialCells(xlCellTypeConstants).EntireRow.Delete
        End If
    End If

    Set dicRowIndexesToDelete = Nothing
    Set cell = Nothing
    Set rangeOfInterest = Nothing
End Sub

请注意,所有行都会立即删除,以获得更好的性能。只有当不超过8个192个独立的岛屿时,这才有效。要删除的行;除此之外,SpecialCells方法将失败。必须单独处理单个单元格范围的特殊情况,因为SpecialCells将整个工作表视为其搜索区域(如果应用于单个单元格)。

答案 2 :(得分:1)

这是一个概念证明,可以解决您面临的问题。您可以将For Loops分配给1维Row,而不是删除Array中的行,然后构建字符串并在{{1}之外一次删除所有行}}

在填写前7行的工作表上运行此操作,然后点击播放并观看。

Loop

如何将其整合到您的代码中

其中Sub DeletingRows() Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets(1) Dim myArr(0 To 2) As Long Dim myStr As String myArr(0) = 2 myArr(1) = 4 myArr(2) = 6 For Each myRow In myArr myStr = myStr & myRow & ":" & myRow & "," Next myRow myStr = Left(myStr, Len(myStr) - 1) ws.Range(myStr).EntireRow.Delete End Sub 是从0开始的长。

x