为什么这个for循环不处理完整的数据集?

时间:2010-06-24 18:16:29

标签: vba excel-vba loops for-loop excel

背景

我有一个事件的票证分配电子表格。电子表格的每一行都是名称和分配的票数。

The Spreadsheet http://s3.amazonaws.com/twitpic/photos/full/120237739.png?AWSAccessKeyId=0ZRYP5X5F6FSMBCCSE82&Expires=1277404609&Signature=pGRx%2Fxcm3InEY2PyKd3k09hC7Xo%3D

我需要更改电子表格,以便每个票证在不同的行上复制一次,例如:

The Spreadsheet after changes http://s3.amazonaws.com/twitpic/photos/full/120238390.png?AWSAccessKeyId=0ZRYP5X5F6FSMBCCSE82&Expires=1277404546&Signature=xrUAdzyIJWKGnrge%2FCD4EudiyX8%3D

我有一个宏来做这件事,但它表现出奇怪的行为

问题

宏不会遍历整个数据集。单步执行代码表明,尽管故意增加LastRow的值,但For循环仅循环指定原始值的许多倍。在每次迭代结束时LastRow的新值似乎被忽略了。

这似乎特别奇怪,因为等效的Do While循环工作正常(请参阅下面的使用Do While循环的工作代码)

问题

为什么会出现问题部分(上面)中描述的行为,为什么它与等效结构不一致?

For循环宏

Sub InsertSurnames()

    Dim LastRow As Long
    Dim r As Long
    Dim surname As String
    Dim tickets As Integer
    Dim surnameCol As Integer
    Dim ticketCol As Integer
    Dim targetCol As Integer

    surnameCol = 1
    ticketCol = 3
    targetCol = 4
    LastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row

    For r = 1 To LastRow

        surname = Cells(r, surnameCol).Value
        tickets = Cells(r, ticketCol).Value


        If (Not (Len(surname) = 0)) Then

            Cells(r, targetCol).Value = surname

            For x = 1 To tickets - 1

                Cells(r + x, 1).EntireRow.Insert
                Cells(r + x, targetCol).Value = surname



            Next x

            LastRow = LastRow + tickets - 1

        End If


    Next r

End Sub

Do While循环宏

Sub InsertSurnames()

    Dim LastRow As Long
    Dim r As Long
    Dim surname As String
    Dim tickets As Integer
    Dim surnameCol As Integer
    Dim ticketCol As Integer
    Dim targetCol As Integer

    surnameCol = 1
    ticketCol = 3
    targetCol = 4
    LastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
    r = 1

    Do While r <= LastRow

        surname = Cells(r, surnameCol).Value
        tickets = Cells(r, ticketCol).Value


        If (Not (Len(surname) = 0)) Then

            Cells(r, targetCol).Value = surname

            For x = 1 To tickets - 1

                Cells(r + x, 1).EntireRow.Insert
                Cells(r + x, targetCol).Value = surname



            Next x

            LastRow = LastRow + tickets - 1

        End If

        r = r + 1
    Loop

End Sub

3 个答案:

答案 0 :(得分:8)

编译器以不同方式交互'For'Loop构造,并使用不同的程序集调用将临时变量放入CPU缓存中,因此在每次迭代之后它不需要返回RAM来读取变量,它可以从cpu的缓存中抓取它。这是为了提高性能,这就是为什么'For'循环通常比'While'循环更快。 'for'循环的限制变量仍然存在于内存中,但在每次迭代期间都不会读取它。因此,如果更改用于最初设置上限的变量,则循环仍将运行到您将其设置为的原始边界。 while循环在每次迭代时检查其exit子句,而不缓存是变量。通常,当你有一定数量的迭代时,应该使用'For'循环,而不是当你不确定需要循环多少次而需要更多动态控制的while循环时。

答案 1 :(得分:3)

要继续使用For...Next循环,您可以执行以下操作:

For r = LastRow To 1 Step -1
    surname = Cells(r, surnameCol).Value
    tickets = Cells(r, ticketCol).Value

    If (Not (Len(surname) = 0)) Then
        Cells(r, targetCol).Value = surname

        For x = 1 To tickets - 1
            Cells(r + x, 1).EntireRow.Insert
            Cells(r + x, targetCol).Value = surname
        Next x

        LastRow = LastRow + tickets - 1
    End If
Next r

如果您想在循环内插入或删除Worksheet上的行,通常最好从最后开始并向后工作。这意味着在大多数情况下您不必调整循环索引

答案 2 :(得分:1)

这是VB中的设计。 for循环的限制只计算一次并保存在临时变量中,就在循环开始之前。因此,如果更改计算限制的变量的值,则不会影响临时变量。虽然这会产生你遇到的意想不到的效果,但它的优点是限制只计算一次,所以此计算中使用的任何方法只输入一次,可能会更快地循环。