当以下代码运行时,它不会完整地完成。我通常需要再运行几次以确保检查该范围内的所有数据,并在符合我的标准时删除该行。
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
符合条件时,它有时会跳过它,然后重新运行代码,它将被删除。
答案 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