VB最强大的功能之一是能够循环访问集合中的对象而不引用索引 - for each
循环。
我发现只想从集合中删除对象非常有用。
当从预定义的表格(如电子表格中的行)中删除对象时,如果我使用索引并从最大值开始并返回第一个,则代码更简单。 (带迭代器的步骤-1)(否则需要一个偏移量,因为For每个都会在删除活动对象后将枚举器指针移回上一个对象)
例如
For intA = 10 to 1 step -1
' ...
Next
使用For Each时怎么样?下一个 例如
For each rngCell in Selection.Cells
' ...
Next
如何使用for each
循环语法循环向后?
答案 0 :(得分:20)
使用for each循环语法不可能向后循环。
作为替代,您可以使用For i = a To 1 Step -1
循环:
Sub reverseForEach()
Dim i As Long, rng As Range
Set rng = ActiveSheet.Range("A1:B2")
For i = rng.Cells.Count To 1 Step -1
Debug.Print rng.item(i).Address
' Or shorthand rng(i) as the Item property
' is the default property for the Range object.
' Prints: $B$2, $A$2, $B$1, $A$1
Next i
End Sub
这适用于具有Item属性的所有集合。例如,工作表,区域或形状。
注意:在Range对象上使用时循环的顺序是从右到左,然后是向上。
答案 1 :(得分:19)
对于内置馆藏(例如Range
),简短的回答是:你不能。对于用户定义的集合,由@VBlades 链接的答案可能有用,尽管成本可能超过利益。
一种解决方法是分离要从实际删除中删除的项目的标识。例如,对于范围,使用Union
构建新的范围变量,然后处理该变量,例如一次删除所有行。对于Range
示例,您还可以利用Variant Array
方法进一步加快速度。
这些内容是否有用取决于您的实际使用情况。
答案 2 :(得分:2)
还有其他很好的答案,但这是另一种通过范围“向后退”的替代方法。
此函数返回一个可以与For..Each
一起使用的 “向后范围数组” :
Function ReverseRange(rg As Range) As Range()
Dim arr() As Range, r As Long, c As Long, n As Long
With rg
ReDim arr(1 To .Cells.Count) 'resize Range Array
For r = .Cells(.Rows.Count, 1).Row To .Cells(1, 1).Row Step -1
For c = .Cells(1, .Columns.Count).Column To .Cells(1, 1).Column Step -1
n = n + 1
Set arr(n) = .Worksheet.Cells(r, c) 'set cell in Array
Next c
Next r
End With
ReverseRange = arr 'return Range Array as function result
End Function
Sub test()
Dim oCell
For Each oCell In ReverseRange(ActiveSheet.Range("E5:A1"))
Debug.Print oCell.Address 'do something here with each cell
Next oCell
End Sub
答案 3 :(得分:0)
使用第二个设置为您想要的计数器的变量,并在您的代码中使用此变量
'ex: Loop from n = 19 to 16
For i = 0 To 3
n = 19 - i
'your code here using n as the counter
Next
答案 4 :(得分:0)
仅适用于范围集合。如果它们具有1个以上的区域,则会更加复杂。
基本上有两个循环,第一个循环将数组中所有单元的索引保留下来,第二个循环创建从后到前的范围并集
Option Explicit
Private Sub Main()
Dim InvertedRange As Range
Set InvertedRange = InvertRange(Application.Union(ActiveSheet.Range("A1:A2"), _
ActiveSheet.Range("F6:F7"), ActiveSheet.Range("E4:F5"), ActiveSheet.Range("E1")))
Dim ActualRange As Range
For Each ActualRange In InvertedRange
Debug.Print (ActualRange.Address(False, False) & " : " & ActualRange.Value)
Next ActualRange
End Sub
Public Function InvertRange(ByVal rngRange_I As Range) As Range
Dim RangesArray() As Long
ReDim RangesArray(1 To rngRange_I.Count, 1 To rngRange_I.Count)
Dim ActualArea As Range
Dim ActualRange As Range
Dim ArrayIndex As Long
For Each ActualArea In rngRange_I.Areas
For Each ActualRange In ActualArea
ArrayIndex = ArrayIndex + 1
RangesArray(ArrayIndex, 1) = ActualRange.Row
RangesArray(ArrayIndex, 2) = ActualRange.Column
Next ActualRange
Next ActualArea
Dim ActualRow As Long
Dim ActualColumn As Long
ActualRow = RangesArray(UBound(RangesArray, 1), 1)
ActualColumn = RangesArray(UBound(RangesArray, 2), 2)
With rngRange_I.Worksheet
Dim InvertedRange As Range
Set InvertedRange = .Cells(ActualRow, ActualColumn)
For ArrayIndex = UBound(RangesArray, 1) To LBound(RangesArray, 1) Step -1
ActualRow = RangesArray(ArrayIndex, 1)
ActualColumn = RangesArray(ArrayIndex, 2)
Set InvertedRange = Application.Union(InvertedRange, _
.Cells(ActualRow, ActualColumn))
Next ArrayIndex
End With
Set InvertRange = InvertedRange
End Function