每个循环的反向顺序

时间:2014-06-23 03:54:28

标签: excel vba excel-vba foreach

VB最强大的功能之一是能够循环访问集合中的对象而不引用索引 - for each循环。

我发现只想从集合中删除对象非常有用。

当从预定义的表格(如电子表格中的行)中删除对象时,如果我使用索引并从最大值开始并返回第一个,则代码更简单。 (带迭代器的步骤-1)(否则需要一个偏移量,因为For每个都会在删除活动对象后将枚举器指针移回上一个对象)

例如

For intA = 10 to 1 step -1 
    ' ...
Next

使用For Each时怎么样?下一个 例如

For each rngCell in Selection.Cells
    ' ...
Next

如何使用for each循环语法循环向后

5 个答案:

答案 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