首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在VBA (excel)中循环遍历行的最有效/最快的方法是什么?

在VBA (excel)中循环遍历行的最有效/最快的方法是什么?
EN

Stack Overflow用户
提问于 2011-11-18 13:27:39
回答 3查看 147.2K关注 0票数 24

我知道Excel中的VBA不是最快的--但我需要最有效(即最快)的方式来遍历大量的行样本。

目前我有:

代码语言:javascript
运行
复制
For Each c In Range("$A$2:$A$" & Cells(Rows.count, "A").End(xlUp).row
    ' do stuff
Next c

“做东西”包括在这里和那里插入一行(所以我需要保持对范围的动态查找)。

有什么想法(看看10,000 rows+)?

编辑我已经在使用

代码语言:javascript
运行
复制
Application.ScreenUpdating = False
Application.Calculation = xlManual
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-11-18 13:53:38

如果您只是循环通过列A中的10k行,那么将该行转储到一个变量数组中,然后循环通过该数组。

然后,您可以将元素添加到新数组中(在需要时添加行),然后使用Transpose()一次性将数组放到您的范围中,或者您可以使用迭代器变量来跟踪您所在的行并以这种方式添加行。

代码语言:javascript
运行
复制
Dim i As Long
Dim varray As Variant

varray = Range("A2:A" & Cells(Rows.Count, "A").End(xlUp).Row).Value

For i = 1 To UBound(varray, 1)
    ' do stuff to varray(i, 1)
Next

下面是一个如何在计算每个单元格后添加行的示例。本例只是在A列中包含单词"foo“的每一行之后插入一行,而不是在插入期间将"+2”添加到变量i,因为我们是从A2开始的。如果我们从A1开始我们的阵列,它将是+1。

代码语言:javascript
运行
复制
Sub test()

Dim varray As Variant
Dim i As Long

varray = Range("A2:A10").Value

'must step back or it'll be infinite loop
For i = UBound(varray, 1) To LBound(varray, 1) Step -1
    'do your logic and evaluation here
    If varray(i, 1) = "foo" Then
       'not how to offset the i variable 
       Range("A" & i + 2).EntireRow.Insert
    End If
Next

End Sub
票数 38
EN

Stack Overflow用户

发布于 2011-11-18 14:33:18

编辑总结和建议

使用for each cell in range构造本身并不慢。缓慢的是在循环中重复访问Excel (无论是读取或写入单元格值、格式等,还是插入/删除行等)。

什么太慢完全取决于你的需求。如果很少使用,需要几分钟运行的Sub可能还可以,但是如果频繁运行,则需要10秒的Sub可能会太慢。

因此,一些一般性的建议:

  1. 让它一开始变得简单。如果结果对于您的需求来说太慢,那么optimise
  2. 专注于优化循环的内容
  3. 不只是假设需要循环。有时你需要在循环内使用单元格值(很多),将它们加载到循环外的变量数组中。
  4. 避免alternatives
  5. if的复杂性的一个好方法是自下而上地循环范围

(for index = max to min step -1)

  • if你不能这样做,而且你的“到处插入行”并不是太多,考虑在每次插入后重新加载数组如果你需要访问value以外的单元格属性,你会被单元格所困删除一些行考虑在循环中建立一个对多区域区域的区域引用,然后在循环

之后一次性删除该区域

例如(未测试!)

代码语言:javascript
运行
复制
Dim rngToDelete as range
for each rw in rng.rows
    if need to delete rw then

        if rngToDelete is nothing then
            set rngToDelete = rw
        else
            set rngToDelete = Union(rngToDelete, rw)
        end if

    endif
next
rngToDelete.EntireRow.Delete

原始帖子

传统观点认为,循环遍历单元格是不好的,而循环遍历变量数组是好的。我也是这方面的拥护者已经有一段时间了。你的问题引起了我的思考,所以我做了一些简短的测试,得到了令人惊讶的(无论如何)结果:

测试数据集: cells A1中的一个简单列表。A1000000 (即1,000,000行)

测试用例1:循环数组

代码语言:javascript
运行
复制
Dim v As Variant
Dim n As Long

T1 = GetTickCount
Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells
v = r
For n = LBound(v, 1) To UBound(v, 1)
    'i = i + 1
    'i = r.Cells(n, 1).Value 'i + 1
Next
Debug.Print "Array Time = " & (GetTickCount - T1) / 1000#
Debug.Print "Array Count = " & Format(n, "#,###")

结果:

代码语言:javascript
运行
复制
Array Time = 0.249 sec
Array Count = 1,000,001

测试用例2:循环范围

代码语言:javascript
运行
复制
T1 = GetTickCount
Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells
For Each c In r
Next c
Debug.Print "Range Time = " & (GetTickCount - T1) / 1000#
Debug.Print "Range Count = " & Format(r.Cells.Count, "#,###")

结果:

代码语言:javascript
运行
复制
Range Time = 0.296 sec
Range Count = 1,000,000

因此,循环数组的速度更快,但仅提高了19% -远远低于我的预期。

测试3:使用单元格引用循环数组

代码语言:javascript
运行
复制
T1 = GetTickCount
Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells
v = r
For n = LBound(v, 1) To UBound(v, 1)
    i = r.Cells(n, 1).Value
Next
Debug.Print "Array Time = " & (GetTickCount - T1) / 1000# & " sec"
Debug.Print "Array Count = " & Format(i, "#,###")

结果:

代码语言:javascript
运行
复制
Array Time = 5.897 sec
Array Count = 1,000,000

测试用例4:具有单元格引用的循环范围

代码语言:javascript
运行
复制
T1 = GetTickCount
Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells
For Each c In r
    i = c.Value
Next c
Debug.Print "Range Time = " & (GetTickCount - T1) / 1000# & " sec"
Debug.Print "Range Count = " & Format(r.Cells.Count, "#,###")

结果:

代码语言:javascript
运行
复制
Range Time = 2.356 sec
Range Count = 1,000,000

因此,在使用单个简单单元格引用的情况下,循环速度要慢一个数量级,更重要的是,范围循环的速度要快两倍!

因此,结论是,最重要的是在循环内执行什么操作,如果速度确实很重要,请测试所有选项

FWIW,在Excel2010 32位、Win7 64位上测试所有测试

  • ScreenUpdating off、
  • Calulation manual、
  • Events disabled。
票数 20
EN

Stack Overflow用户

发布于 2017-03-14 16:36:16

由于某些原因,For Each比I=1 to X快得多。试着翻一遍同样的字典,

对于dDict中的每个Dkey,

和一次for Dkey = lbound(dDict.keys) to ubound(dDict.keys)

即使您正在经历相同的构造,=>You也会注意到巨大的不同。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8178161

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档