【问题标题】:Create an empty 2d array创建一个空的二维数组
【发布时间】:2020-04-21 09:55:52
【问题描述】:

我不喜欢未初始化的 VBA 数组,因为每次使用 UBound()For Each 之前都必须检查 if array is initialized 以避免异常,并且没有本地 VBA 函数来检查它。这就是我初始化数组的原因,至少用a = Array() 将它们清空。这在大多数情况下消除了额外检查的需要,因此一维数组没有问题。

出于同样的原因,我尝试创建一个空的二维数组。不可能简单地做ReDim a(0 To -1, 0 To 0),转置一维空数组或类似的东西。我偶然遇到的唯一方法是使用MSForms.ComboBox,将空数组分配给.List 属性并将其读回。下面是例子,在 Excel 和 Word 中工作,你需要在 VBA 项目中插入UserForm,在上面放置ComboBox,并添加以下代码:

Private Sub ComboBox1_Change()

    Dim a()
    ComboBox1.List = Array()
    a = ComboBox1.List
    Debug.Print "1st dimension upper bound = " & UBound(a, 1)
    Debug.Print "2nd dimension upper bound = " & UBound(a, 2)

End Sub

组合更改后的输出是:

1st dimension upper bound = -1
2nd dimension upper bound = 0

其实debug中确实是空的二维数组:

有没有更优雅的方法来创建一个空的二维数组,而不使用ComboBoxUserForm 控件?

【问题讨论】:

  • 我不知道答案,但我确实找到了一种让 excel 崩溃的好方法。我想知道这是否会影响其他人。尝试仅在子例程中编写以下行(先保存您的工作):a=Array();redim a(,0 to 0)
  • @JNevill 瞬间崩溃!
  • 你现在让我玩这个
  • 我认为这是一个 XY 问题。您应该问的是 如何轻松检查数组是否已初始化? 。 CPearsom.com here 上提供了一个很好的解决方案
  • 我必须承认这个问题本身可能听起来很宽泛,因此很容易被视为 XY 问题。请注意,我已经发布了链接how to check if array is initialized,IMO OERN 之类的方法必须是最后的手段,使用它们的唯一借口是显着的简单性和对他人的性能。真正的重点是要改变二维数组处理模式并摆脱额外的检查。你知道,“如果一开始这个想法不是荒谬的,那么它就没有希望了。”

标签: arrays excel vba multidimensional-array is-empty


【解决方案1】:

Idk 伙计 - 我认为你偶然发现这处房产很疯狂。

我可能会在这里停下来做:

Function Empty2DArray() As Variant
With CreateObject("Forms.ComboBox.1")
    .List = Array()
    Empty2DArray = .List
End With
End Function

并像这样使用它:a = Empty2DArray

您不需要创建用户表单或组合框 - 您可以使用 CreateObject

但正如其他人所说,在检查数组是否已初始化时进行错误处理可能更有意义。

【讨论】:

    【解决方案2】:

    这仅适用于 Windows(不适用于 Mac):

    Option Explicit
    
    #If Mac Then
    #Else
        #If VBA7 Then
            Private Declare PtrSafe Function SafeArrayCreate Lib "OleAut32.dll" (ByVal vt As Integer, ByVal cDims As Long, ByRef rgsabound As SAFEARRAYBOUND) As LongPtr
            Private Declare PtrSafe Function VariantCopy Lib "OleAut32.dll" (pvargDest As Any, pvargSrc As Any) As Long
            Private Declare PtrSafe Function SafeArrayDestroy Lib "OleAut32.dll" (ByVal psa As LongPtr) As Long
        #Else
            Private Declare Function SafeArrayCreate Lib "OleAut32.dll" (ByVal vt As Integer, ByVal cDims As Long, ByRef rgsabound As SAFEARRAYBOUND) As Long
            Private Declare Function VariantCopy Lib "OleAut32.dll" (pvargDest As Variant, pvargSrc As Any) As Long
            Private Declare Function SafeArrayDestroy Lib "OleAut32.dll" (ByVal psa As Long) As Long
        #End If
    #End If
    
    Private Type SAFEARRAYBOUND
        cElements As Long
        lLbound As Long
    End Type
    Private Type tagVariant
        vt As Integer
        wReserved1 As Integer
        wReserved2 As Integer
        wReserved3 As Integer
        #If VBA7 Then
            ptr As LongPtr
        #Else
            ptr As Long
        #End If
    End Type
    
    Public Function EmptyArray(ByVal numberOfDimensions As Long, ByVal vType As VbVarType) As Variant
        'In Visual Basic, you can declare arrays with up to 60 dimensions
        Const MAX_DIMENSION As Long = 60
        
        If numberOfDimensions < 1 Or numberOfDimensions > MAX_DIMENSION Then
            Err.Raise 5, "EmptyArray", "Invalid number of dimensions"
        End If
    
        #If Mac Then
            Err.Raise 298, "EmptyArray", "OleAut32.dll required"
        #Else
            Dim bounds() As SAFEARRAYBOUND
            #If VBA7 Then
                Dim ptrArray As LongPtr
            #Else
                Dim ptrArray As Long
            #End If
            Dim tVariant As tagVariant
            Dim i As Long
            '
            ReDim bounds(0 To numberOfDimensions - 1)
            '
            'Make lower dimensions [0 to 0] instead of [0 to -1]
            For i = 1 To numberOfDimensions - 1
                bounds(i).cElements = 1
            Next i
            '
            'Create empty array and store pointer
            ptrArray = SafeArrayCreate(vType, numberOfDimensions, bounds(0))
            '
            'Create a Variant pointing to the array
            tVariant.vt = vbArray + vType
            tVariant.ptr = ptrArray
            '
            'Copy result
            VariantCopy EmptyArray, tVariant
            '
            'Clean-up
            SafeArrayDestroy ptrArray
        #End If
    End Function
    

    您现在可以创建具有不同维数和数据类型的空数组:

    Sub Test()
        Dim arr2D() As Variant
        Dim arr4D() As Double
        '
        arr2D = EmptyArray(2, vbVariant)
        arr4D = EmptyArray(4, vbDouble)
        Stop
    End Sub
    

    【讨论】:

      猜你喜欢
      • 2011-09-30
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      • 2016-12-27
      • 1970-01-01
      • 2016-04-23
      • 2020-08-02
      相关资源
      最近更新 更多