每行而不是列的每个循环非连续

时间:2019-01-16 14:53:00

标签: excel vba

我有一个跨越行和列的不连续选择,并且我想对其进行For Each循环。 Excel VBA通​​过首先向下循环第1列,然后向下循环2,3等来做到这一点;但我希望它先沿行循环。

(我的工作表看起来像下面的图片,我需要依次循环选择(版本)每列,并检索文档号和其他信息。工作表中的行数和版本列数为不固定)。

写一个相当大的Sort函数并创建一个引用数组的时间很短,我想知道是否有一种“内置”方式来做到这一点?

我不需要代码,只需一个解释。

Non-contiguous selection

3 个答案:

答案 0 :(得分:2)

For Each迭代对象集合的顺序与实现有关(IOW责备Excel,而不是VBA),并且尽管可能是确定的和可预测的,但其规范中没有任何内容可以保证特定的迭代顺序。因此,为迭代对象集合而编写的VBA代码不应在特定的迭代顺序的假设下编写,因为在所涉及的类型库的各个版本(此处为Excel)之间可以很好地进行更改。

尚不清楚Range / Selection的形状是什么,但是如果您需要以特定顺序迭代选定的单元格,则不应使用For Each循环,至少不是为了迭代细胞本身。

由于范围不连续,因此Range将具有多个Areas;您需要迭代Selection.Areas,然后为每个选定区域 进行特定顺序的迭代。到目前为止,For EachRange.Areas的{​​{3}}。

Debug.Assert TypeOf Selection Is Excel.Range

Dim currentArea As Range
For Each currentArea In Selection.Areas
    'todo
Next

创建一个以currentArea作为参数的单独过程,而不是most efficient way to iterate an object collection-在该过程中,您将迭代各个单元格:

Private Sub ProcessContiguousArea(ByVal area As Range)
    Dim currentRow As Long
    For currentRow = 1 To area.Rows.Count
        Debug.Print area.Cells(currentRow, 1).Address
    Next
End Sub

现在,外循环看起来像这样:

Debug.Assert TypeOf Selection Is Excel.Range

Dim currentArea As Range
For Each currentArea In Selection.Areas
    ProcessContiguousArea currentArea
Next

ProcessContiguousArea过程可以自由地执行给定连续区域所需的任何操作,只需使用For循环逐行迭代范围,而无需关心实际的地址。选定区域:使用Range.Cells(RowIndex, ColumnIndex),第1行/第1列代表该范围的左上角单元,无论该范围在工作表中位于何处。

可以使用Range.Offset访问未选择的单元格:

        Debug.Print area.Cells(currentRow, 1).Offset(ColumnOffset:=10).Address

area返回工作表上area.Row左上角单元格的行,而工作表上area的左上角单元格列则用{{ 1}}。

答案 1 :(得分:1)

不连续

通过首先遍历 i ),您将获得“ 按行顺序”,例如A1,B1,C1,...

代码

Sub NonContiguous()

    Dim i As Long
    Dim j As Long
    Dim k As Long

    With Selection
        For k = 1 To .Areas.Count
            With .Areas(k)
                For i = .Row To .Rows.Count + .Row - 1
                     For j = .Column To .Columns.Count + .Column - 1

                         Debug.Print .Parent.Cells(i, j).Address & " = " _
                                 & .Parent.Cells(i, j)

                     Next
                Next
            End With
        Next
    End With

End Sub

答案 2 :(得分:0)

这是基于urdearboy的建议:

1.遍历列
2.在列中,遍历单元格

Sub disjoint()
    Dim r As Range, rInt As Range
    Dim nLastColumn As Long
    Dim nFirstColumn As Long, msg As String
    Dim N As Long

    Set r = Range("C3,C9,E6,E13,E15,G1,G2,G3,G4")

    nFirstColumn = Columns.Count
    nLastColumn = 0
    msg = ""

    For Each rr In r
        N = rr.Column
        If N < nFirstColumn Then nFirstColumn = N
        If N > nLastColumn Then nLastColumn = N
    Next rr

    For N = nFirstColumn To nLastColumn
        Set rInt = Intersect(Columns(N), r)
        If rInt Is Nothing Then
        Else
            For Each rr In rInt
                msg = msg & vbCrLf & rr.Address(0, 0)
            Next rr
        End If
    Next N
    MsgBox msg
End Sub

enter image description here