【问题标题】:Can you declare jagged arrays in excel VBA directly?你可以直接在excel VBA中声明锯齿状数组吗?
【发布时间】:2013-11-07 04:11:27
【问题描述】:

在我的项目中,我经常使用锯齿状数组,即元素也是数组的数组。

直到知道我才设法像这样定义这些数组:

dim subarray(1 to 3) as Integer
dim MyArray(1 to 5) as Variant
subarray(1) = 40
subarray(2) = 50
subarray(3) = 60

MyArray(1) = subarray

但我想做这样的事情:

dim MyArray(1 to 5)(1 to 3) as Variant/Integer
MyArray(1)(1) = 40

上面的例子不能编译。有没有类似的有效方式直接声明嵌套数组?

编辑:正确的术语是“锯齿状数组”而不是“嵌套数组”。

EDIT2:编辑了示例值,以防止索引和值之间的混淆。

【问题讨论】:

  • 请注意,我正在寻找声明嵌套数组的方法,而不是多维数组。我不确定嵌套是不是正确的词,但它与多维数组不同。
  • 您的示例无法编译,因为不遵循 VBA 规则(或我知道的任何编程语言规则):您不能为同一个变量设置两种不同的类型。此外,您错误地声明了 2D 数组。与其尝试脑海中出现的第一个字符组合,不如进行一些研究/学习(或者甚至在这里问:“我怎样才能声明一个二维数组?”-> 反正有点离题了);但是您尝试的确切意义是什么?为什么你认为它会起作用?
  • 在阅读了您的最后一条评论后,我有点好奇:当时尝试的确切点是什么……您所谓的嵌套数组是在您的第一个代码中完成的;你想在第二段代码中做什么?
  • 锯齿状阵列可以工作吗? stackoverflow.com/a/9436309/2258
  • @varocarbas 我不想让你声明一个二维数组。第一个示例确实编译。然后将 MyArray 声明为变体,并将其子数组(在本例中为一个)声明为整数。我试图在第二个示例中实现相同的结果,但没有过度声明辅助变量。请注意,这在例如 Matlab 中是可能的。然后 MyArray 将具有数据类型 Cell,它可以在每个位置包含数组。

标签: arrays excel vba


【解决方案1】:

数组数组:

Dim aa(), ax(),  dd,  x(), xx(), x2()  ' all are " As Variant"

' Array of Arrays - Variant(0 To 2) with 3 Variant(0 To 2) ( 3 Variant/Integer each )
aa = Array( Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9) )
aa(0)(0) = 0

' Array of "Excel" arrays - Variant(0 To 2) with 3 Variant(1 To 3) (3 Variant/Integer each)
ax = Array([{1,2,3}], [{4,5,6}], [{7,8,9}])
ax(0)(1) = 0

另一种选择是Collection of Collections,或Dictionary of Dictionaries:

Set dd = CreateObject("Scripting.Dictionary")
Set dd(2) = CreateObject("Scripting.Dictionary")
dd(2)(4) = 24


一些“Excel”矩形数组示例(因为不是 VBA 类型并且也适用于 Excel 公式):
' "row" array starts at 1 - Variant(1 To 3) with 3 Variant/Integer each
x = [{1,2,3}]
x(1) = 0

' "column" array starts at 1, 1 - Variant(1 To 3, 1 To 1)
xx = [{1;2;3}]
xx(1, 1) = 0

' "Excel" rectangular array - Variant(1 To 3, 1 To 3)
x2 = [{1,2,3;4,5,6;7,8,9}]
x2(1, 1) = 0

Stop ' pause to check the types in the Locals window

【讨论】:

    【解决方案2】:

    在 VBA 中有多种方法可以拥有集合的集合。它们都有优点和缺点。

    多维数组

    好:

    • 语法简单(只有一个变量)
    • 类型安全。 Integer 矩阵的所有元素都是已知的并强制为Integers。
    • 非常快速的数组访问

    不好:

    • 如果内部数组的大小差异很大,则矩阵会浪费一些空间,因为矩阵中有未使用的“单元格”。
    • 您只能使用ReDim Preserve 更改最后一个维度的边界。所以你不能在不清除所有数据的情况下向矩阵添加“列”。

    通过包含多个用逗号分隔的边界来声明多维数组:

    Dim intMatrix(0 to 2, 0 to 4) As Integer
    

    如果你首先声明一个没有任何边界的数组,你可以动态增加一个多维数组的最后一个维度:

    Dim intMatrix() As Integer                ' Uninitialized dynamic array
    ReDim intMatrix(0 to 4, 0 to 2)           ' Initialize as a matrix
    ReDim Preserve intMatrix(0 to 4, 0 to 3)  ' Add another "row" to the matrix, preserving existing data
    

    锯齿状数组

    好:

    • 灵活

    不好:

    • 您失去了编译时类型安全性
    • 由于嵌套结构,它们有点棘手/混乱
    • 调整内部数组的大小既麻烦又昂贵

    您可以通过声明Variant() 类型的外部数组并将其他数组分配给外部数组的元素来创建交错数组:

    Dim outer() As Variant  ' Dynamic, so new inner arrays can be added
    Dim inner() As Integer  ' Dynamic, so new elements can be added
    
    ReDim outer(0 to 3)
    ReDim inner(0 to 4)
    outer(2) = inner
    

    丢失编译时类型信息

    所有编译器“知道”外部数组是它可以包含任何东西。所以下面的代码会编译:

    Set objWorksheet = outer(2)(3)
    

    虽然在运行时这会导致错误,因为outer(2) 的内部数组包含Integers,而不是Worksheet 对象。

    调整大小很尴尬

    交错数组的一个好处是内部数组可以有不同的大小。但是,您不能直接调整内部数组的大小。 VBA 就是无法处理语法;以下内容无法编译:

    ReDim Preserve outer(2)(0 to 5)
    

    为了调整内部数组的大小,您首先必须将内部数组分配给一个单独的变量,调整该变量的大小,然后将其分配回锯齿状数组:

    Dim tempInts() As Integer
    tempInts = outer(2)
    ReDim Preserve tempInts(0 to 5)
    outer(2) = tempInts
    

    您必须将tempInts 重新分配回outer 数组的原因是数组在VBA 中使用按值语义。这意味着当您将数组分配给变量时(如在tempInts = outer(2) 中,您复制整个数组。如果您的数组很长(例如几千个元素),这可能会非常昂贵,如果您的数组包含字符串则更昂贵,因为每个字符串也必须被复制。

    锯齿状集合

    好:

    • 添加和删除元素的简单语法
    • 就像锯齿状数组一样灵活
    • 集合使用按引用语义,因此分配成本很低,并且您可以对同一个集合对象有多个引用

    不好:

    • 像锯齿状数组一样,没有类型安全性

    如果您经常向内部数组添加元素,使用Collection 对象而不是数组会容易得多。 Collections 不强制其元素的数据类型,因此这与使用 Variant 数组具有相同的缺点——但无论如何您必须这样做才能使用锯齿状数组。

    Dim cAnimals As New Collection 
    
    ' Let's add stats on the Cheetah
    Dim cCheetah As New Collection
    
    ' Easy to add inner collections to the outer collection.  Also, cCheetah refers
    ' to the same collection object as cAnimals(1).  
    cAnimals.Add cCheetah          
    
    ' Easy to add items to inner collection.
    ' Working directly with the cCheetah collection:
    For Each vMeasurment In GetMeasurements("Cheetah")
        cCheetah.Add vMeasurement
    Next
    
    ' Working on the same collection by indexing into the outer object
    For i = 1 To cAnimals.Count
        For j = 1 To cAnimals(i).Count
            cAnimals(i)(j) = cAnimals(i)(j) * dblNormalizingFactor
        Next
    Next
    

    【讨论】:

      【解决方案3】:

      正如 Joshua 所说:没有用于直接声明锯齿状数组的特定 VBA 语法。
      但锯齿状数组遵循正常的 VBA 赋值规则:例如

      Dim a as integer
      dim v as variant
      a=17
      v=a
      a=19
      

      你不希望 V 现在等于 19!

      【讨论】:

      • 原始值使用按值语义并不奇怪。奇怪的是数组本身(包装数组对象,而不是单个元素)使用按值语义。例如,尝试使用数组类型的 Property(不是字段)创建一个 Class 模块。您会发现,每次调用属性 get 方法时,您都将索引到一个新的数组副本中,并且永远不会更改类实例“拥有”的数组的值。
      • 数组为什么要有不同的规则?指针是,指针数组是,对象是,对象数组是,简单数据类型数组不是。 C 的工作方式相同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-06
      • 2013-04-21
      • 2018-09-27
      • 2023-03-03
      相关资源
      最近更新 更多