删除行(向后工作),但使用范围变量吗?

时间:2018-11-01 18:35:36

标签: excel vba delete-row

通常,您需要遍历一系列单元格,并根据某些条件删除整个行。

在实践中,最好从范围的结束开始并逐步进行。

Dim i as Long
For i = lastRow to 1 Step -1
    If Cells(i, 2).Value = "del" then Rows(i).EntireRow.Delete
End if

但是,大多数时候我都在使用Range对象。

是否有一种不需要使用For i类型循环的范围对象向后工作的方法?

Dim rng as Range, cel as Range
Set rng = Range("A1:A100")

For each cel in rng step -1
   if cel.value = "del" then cel.EntireRow.Delete
next cel

我期望Expected: End of Statement部分出现Step -1错误(无双关语)。

这个想法是,在尝试向后Cells()变量时,我基本上不必将数据重新排列到Range中。我发现一堆使用范围变量有点麻烦,但是如果要从该范围中删除行,则必须切换为使用Cells([long],[long])

编辑:刚想出了这个,但仍然感觉很笨拙:

Dim k As Long, cel as Range
Set cel = rng.cells(rng.cells.count)
For k = cel.Row To rng.Cells(1).Row Step -1
    If rng.Cells(k).Value = "del" Then rng.Cells(k).EntireRow.Delete
Next k

3 个答案:

答案 0 :(得分:6)

是的,您可以不使用For i =语句来执行此操作。只需创建一个特殊的范围,完成循环即可将其删除。

Dim cel As Range, rng As Range
Dim delRng As Range

For Each cel In rng
    If cel.Value = "del" Then
        If delRng Is Nothing Then
            Set delRng = cel
        Else
            Set delRng = Union(delRng, cel)
        End If
    End If
Next cel

If Not delRng Is Nothing Then delRng.EntireRow.Delete

您甚至不必后退。

答案 1 :(得分:3)

反之亦然

  

“是否有一种无需使用For i类型循环就可以使用范围对象向后工作的方法?”

除了@ K-Davis的有效解决方案之外,我还将演示如何使用的高级过滤功能 Application.Index方法。它只需要三个参数:

  • 基于整个数据集的2维数据字段数组v
  • 要维护的行号的1维数组,通过辅助函数getAr(v, 1)调用,其中参数1定义了第一列
  • (所有列的1维数组,通过Evaluate自动创建)

此方法不是删除行,而是使用了整个数据集(例如,省略了假定的标题行的A2:C10),并再次写回过滤后的数据字段数组,将其再次分配给rng

主要过程

Sub DelRows()
  Dim rng As Range,  v
  Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A2:C10") ' << change to entire data range
' [1a] create 2-dim data field array (1-based)
  v = rng.Value2
' [1b] filter out rows to be deleted
  v = Application.Transpose(Application.Index(v, getAr(v, 1), Evaluate("row(1:" & rng.Columns.Count & ")")))
' [2] write data field back to resized range
  rng = ""                                  ' clear lines
  rng.Resize(UBound(v), UBound(v, 2)) = v
End Sub

辅助功能getAr()

Function getAr(v, ByVal colNo&) As Variant()
' Purpose: collect row numbers not to be deleted (criteria no "DEL" in 1st column)
' Note:    called by above procedure DelRows
  Dim ar, i&, n&
  ReDim ar(0 To UBound(v) - 1)
  For i = 1 To UBound(v)
      If UCase$(v(i, colNo)) <> "DEL" Then
         ar(n) = i: n = n + 1
      End If
  Next i
  ReDim Preserve ar(0 To n - 1): getAr = ar
End Function

相关的SO链接

Cf。 Insert new first column in datafield array without loops or API calls

答案 2 :(得分:2)

我知道您说过您不喜欢For i,但是恕我直言,这是最干净的方法

For i = rng.Rows.Count To 1 Step -1
    With rng.Cells(i, 2)
        If .Value = "del" then
            .Entirerow.Delete
        End If
    End With
Next

请注意,rng.Cells构造相对于rng

例如,如果rng是A100:A1000,则rng.Cells(rng.Rows.Count, 1)是指A1000