【问题标题】:Efficiency vs functionality in range-type array and non-type array assignment with RangeRange 类型数组和非类型数组赋值中的效率与功能
【发布时间】:2020-06-23 03:44:30
【问题描述】:

我知道这一点;

Arr() =Range("E2:X2500")

...然后用 Arr 做一些事情,然后使用:

Range("E2:X2500")=Arr()

比直接循环和引用单元格更有效(更快)。 这是光速!

但是,这种范围到数组的分配只获取单元格的值。 有没有办法将实际范围(连续或不连续)分配给数组(具有相同的光速),这样您就可以按照引用单元格的方式处理数组项,例如:

arr(23).row 'getting a row number

或者;

If Arr(23).Value ="Pending" then arr(23).font.bold=1 else arr(23).font.bold=0

我知道我可以调暗一个范围类型的数组,其中每个项目都可以存储一个实际的单个单元格范围。但是这个数组不能以同样的方式处理 - 一个班轮分配:

Dim Arr () as Range
Set Arr = Range("E2:X2500") 'error

相反,我需要迭代每个单元格并将其分配给范围类型数组中的下一项,这允许我以引用单元格的方式处理项目,但是因为我正在处理循环,所以加载时间要长得多。

另外,我如何将范围类型的数组转储回工作表中,并且与单行分配一样容易和有效?我认为唯一的方法是再次使用循环,对吗?

附带问题: Speedwise,通过范围类型数组引用单元格比直接通过工作表引用单元格更好,还是两者基本相同?

谢谢!

【问题讨论】:

    标签: arrays excel vba


    【解决方案1】:

    好吧,使用数组会节省很多代码运行时间。但是,有一些问题必须要明白:

    1. 在 VBA 中工作并且您的项目增加时,第一件事就是正确声明您的变量。尝试反射性地将Option Explicit 放在所有模块的顶部。在数组的情况下,从这个角度来看,事情是这样的:

      Dim Arr() As variant, arr1 As Variant

      两种声明都适用于 excel。但推荐使用第二个(根据口味),当您需要一个范围内的数组时。当你想构建一个结果数组时,假设它是从零开始的,你必须注意返回值的范围大小。

    2. 如果元素数量不固定/未知,则无法完全按照您在问题中尝试的方式检索数组内容。看下一段测试代码:

      Sub testArrays() Dim sh As Worksheet, rng As Range, arrTest As Variant Set sh = ActiveSheet Set rng = sh.Range("A1:F4") arrTest = rng.value sh.Range("J1").Resize(UBound(arrTest, 1), UBound(arrTest, 2)).value = arrTest End Sub

    建议使用arrTest = sh.Range("A1:F4").value。使用范围Value。 Excel 能够根据您的声明了解您需要什么,但您最好以某种方式与范围定义方式区分开来。

    有时,您需要在分析动态范围的过程中构建一个数组。如果您不知道新的数组维度,需要重新调整(保留),只能重新调整数组的第二个维度,并且必须使用Transpose 函数,在这种情况下。最后,只有知道数组的行数和列数,结果数组才能正确加载到一个范围内。

    1. 您可以通过以下方式从数组行推导出范围行: 如果我们参考上面的arrTest,我们知道它的第一行是工作表的第一行,它有 5 列。

    所以,arrTest(3, 1) 将是 sh.Range("A3").Value,它的行将是 3。

    那么,arrTest(3, 4) 将是 sh.Range("D3").Value,它的行也是 3。

    如果您的数组来自从第五行开始的范围,则必须添加四个才能获得从数组行中提取的工作表行...

    因此,您的示例可以转换为:

    If arrTest(3, 4) ="Pending" then sh.Cells(3, 4).Font.Bold=1 Else sh.Cells(3, 4).Font.Bold=0

    1. 现在,如果您需要一个范围数组,则无法按照您尝试的方式进行操作。您必须使用范围地址并在末尾构建范围:

      Sub testArraysBis() Dim sh As Worksheet, rng As Range, rng1 As Range, lastCol As Long Dim rng2, arrTest As Variant, arrT As Variant, arrF As Variant Set sh = ActiveSheet lastCol = sh.Cells(1, Cells.Columns.Count).End(xlToLeft).column Set rng = sh.Range(sh.Cells(1, 1), sh.Cells(4, lastCol)) Set rng1 = sh.Range("A5:F6") arrT = Array(rng.Address, rng1.Address) arrTest = rng.value Debug.Print UBound(arrTest), LBound(arrTest) sh.Range("J1").Resize(UBound(arrTest, 1), UBound(arrTest, 2)).value = arrTest Set rng2 = sh.Range(arrT(0)) Debug.Print rng2.Address arrF = sh.Range(arrT(0)).value Debug.Print UBound(arrF, 2) End Sub

    rng2 范围将使用从arrT 数组中提取的地址字符串构建。数组(arrF)也可以从arrT的第一个元素中提取出来……

    1. 结语: 就速度而言,最好的方法是将范围加载到数组中,使用它们进行所有处理(在内存中并且由于这个方面非常快),但最重要的问题是构建另一个数组(甚至一个范围,使用Union) 并一次检索数据。将每个部分处理结果发送到一个单元格/范围会消耗大量时间和其他资源,对于大范围大小...

    【讨论】:

    • 感谢 FaneDuru 非常详细的解释!
    • @Guyglk:很高兴能帮到你!在这种情况下,我们投票赞成答案,更重要的是,最好勾选代码左侧的复选框,使其成为可接受的答案。这样,寻找类似东西的人很容易找到它……这个主题很广泛。如果您需要进一步说明,我很乐意为您提供帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多