删除行(向后工作),但使用范围变量?
Deleting rows (working backwards), but use a range variable?
通常需要遍历一系列单元格,然后根据某些条件删除整行。
在实践中,最好从范围的 end 开始,然后逐步增加。
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
部分,这是我预料的(没有双关语意)。
我的想法是,在尝试对 Range
变量进行逆向处理时,我基本上不必将数据重新排列到 Cells()
中。我发现大量使用范围变量有点笨拙,但是当想要从该范围中删除行时,如果有意义的话,必须切换到使用 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
我知道你说过你不喜欢 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
是的,您可以不使用 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
而且您甚至不必后退。
反过来
"Is there a way to work backwards, with a range object, that doesn't require the use of a For i
type loop?"
除了@K-Davis '有效的解决方案,我还演示了如何使用
Application.Index
方法。它只需要三个参数:
- 基于整个数据集
的二维数据字段数组v
- 要维护的行号的一维数组,通过辅助函数调用
getAr(v, 1)
,其中参数 1
定义第一列
- (所有列的一维数组,通过
Evaluate
自动创建)
这种方法没有删除行,而是使用了整个数据集(例如,A2:C10 省略了假定的标题行)并写回 filtered 数据字段数组,将其分配给再次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
相关SOlink
比照。 Insert new first column in datafield array without loops or API calls
通常需要遍历一系列单元格,然后根据某些条件删除整行。
在实践中,最好从范围的 end 开始,然后逐步增加。
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
部分,这是我预料的(没有双关语意)。
我的想法是,在尝试对 Range
变量进行逆向处理时,我基本上不必将数据重新排列到 Cells()
中。我发现大量使用范围变量有点笨拙,但是当想要从该范围中删除行时,如果有意义的话,必须切换到使用 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
我知道你说过你不喜欢 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
是的,您可以不使用 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
而且您甚至不必后退。
反过来
"Is there a way to work backwards, with a range object, that doesn't require the use of a
For i
type loop?"
除了@K-Davis '有效的解决方案,我还演示了如何使用
Application.Index
方法。它只需要三个参数:
- 基于整个数据集 的二维数据字段数组
- 要维护的行号的一维数组,通过辅助函数调用
getAr(v, 1)
,其中参数1
定义第一列 - (所有列的一维数组,通过
Evaluate
自动创建)
v
这种方法没有删除行,而是使用了整个数据集(例如,A2:C10 省略了假定的标题行)并写回 filtered 数据字段数组,将其分配给再次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
相关SOlink
比照。 Insert new first column in datafield array without loops or API calls