代码之家  ›  专栏  ›  技术社区  ›  chrisbunney Bogdan Calmac

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

  •  4
  • chrisbunney Bogdan Calmac  · 技术社区  · 15 年前

    背景

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

    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循环只循环指定的原始值的多次。新的价值 最后一行 在每次迭代结束时,似乎都被忽略了。

    这看起来特别奇怪,因为等效的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 回复  |  直到 15 年前
        1
  •  8
  •   Fink    15 年前

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

        2
  •  3
  •   barrowc    15 年前

    继续使用 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 从循环内部开始,最好从结尾开始向后工作。这意味着在大多数情况下不需要调整循环索引。

        3
  •  1
  •   Wilhelm    15 年前

    这是用VB设计的。for循环的限制只计算一次,并保存在临时变量中,就在循环开始之前。所以,如果你改变了它计算极限的变量的值,温度变量就不会受到影响。虽然这有您遇到的意外影响,但它的优点是限制只计算一次,因此此计算中使用的任何方法都只输入一次,可能会加快循环速度。

    推荐文章