Excel 编译时维度未知时创建和填充数组

Excel 编译时维度未知时创建和填充数组,excel,vba,Excel,Vba,我正在研究通过VBA进行二进制序列化和反序列化 为此,我需要能够动态地创建和填充任意数量的维度数组。例如,假设您想做以下事情 Dim sample(0 To 3, 0 To 4, 0 To 2, 0 To 2) As Integer sample(3,1,1,0) = 12345 因此,创建并填充一个4维数组。当然,如果您在编译时知道维度,这很容易,但是如果您不知道呢 Sub Deserialize() ' Dynamic equiavalent of: Dim sample(0 To

我正在研究通过VBA进行二进制序列化和反序列化

为此,我需要能够动态地创建和填充任意数量的维度数组。例如,假设您想做以下事情

Dim sample(0 To 3, 0 To 4, 0 To 2, 0 To 2) As Integer
sample(3,1,1,0) = 12345
因此,创建并填充一个4维数组。当然,如果您在编译时知道维度,这很容易,但是如果您不知道呢

Sub Deserialize()

  ' Dynamic equiavalent of: Dim sample(0 To 3, 0 To 4, 0 To 2, 0 To 2) As Integer
  Dim dimensions(0 To 3) As Integer
  dimensions(0) = 3
  dimensions(1) = 4
  dimensions(2) = 2
  dimensions(3) 2
  Dim sample As Variant
  sample = CreateArrayWithDimensions(dimensions)

  ' Dynamic equivalent of sample(3,1,1,0) = 12345
  Dim index(0 To 3) As Integer
  index(0) = 3
  index(1) = 1
  index(2) = 1
  index(3) = 0
  Call SetArrayValue(sample, index, 12345)
End Sub
这有可能吗?或者换句话说,有没有办法实现pseuod函数CreateArrayWithDimensions和SetArrayValue


谢谢

用“字典”代替多维数组怎么样。该键可以是所有索引的串联

添加对Microsoft脚本运行时的引用,或将其更改为后期绑定

Option Explicit

Dim sample As New Scripting.Dictionary

Sub test()
    Dim index(0 To 3) As Integer
    index(0) = 3
    index(1) = 1
    index(2) = 1
    index(3) = 0
    Call SetArrayValue(sample, index, 12345)
    Debug.Print GetArrayValue(sample, index)
End Sub

Sub SetArrayValue(sample As Dictionary, index() As Integer, val As Variant)
    Dim key As String
    key = createIndexKey(index)
    If sample.Exists(key) Then
        sample(key) = val
    Else
        Call sample.Add(key, val)
    End If
End Sub

Function GetArrayValue(sample As Dictionary, index() As Integer) As Variant
    Dim key As String
    key = createIndexKey(index)
    If sample.Exists(key) Then
        GetArrayValue = sample(key)
    Else
        GetArrayValue = Null
    End If
End Function

Function createIndexKey(index() As Integer)
    Dim i As Integer
    createIndexKey = ""
    For i = LBound(index) To UBound(index)
        createIndexKey = IIf(createIndexKey = "", "", ":") & index(i)
    Next i
End Function

没有优雅的解决方案
Redim
无法接受可变数量的参数。但是,如果您可以限制“任意”,您可以尝试以下方法:

Sub DimTest()
    Dim sample() As Integer
    Dim dimensions(0 To 3) As Integer
    Dim index(0 To 3) As Integer

    dimensions(0) = 10
    dimensions(1) = 20
    dimensions(2) = 40
    dimensions(3) = 70
    index(0) = 1
    index(1) = 2
    index(2) = 4
    index(3) = 7

    sample = CreateArrayWithDimensions(dimensions)
    SetArrayValue sample, index, 12345
End Sub

Function CreateArrayWithDimensions(dimensions() As Integer) As Integer()
    Dim b() As Integer

    Select Case UBound(dimensions)
        Case 1: ReDim b(dimensions(0))
        Case 2: ReDim b(dimensions(0), dimensions(1))
        Case 3: ReDim b(dimensions(0), dimensions(1), dimensions(2))
        Case 4: ReDim b(dimensions(0), dimensions(1), dimensions(2), dimensions(3))
        Case 5: ReDim b(dimensions(0), dimensions(1), dimensions(2), dimensions(3), dimensions(4))
    End Select

    CreateArrayWithDimensions = b
End Function

Sub SetArrayValue(sample() As Integer, idx() As Integer, value As Integer)

    Select Case UBound(idx)
        Case 1: sample(idx(0)) = value
        Case 2: sample(idx(0), idx(1)) = value
        Case 3: sample(idx(0), idx(1), idx(2)) = value
        Case 4: sample(idx(0), idx(1), idx(2), idx(3)) = value
        Case 5: sample(idx(0), idx(1), idx(2), idx(3), idx(4)) = value
    End Select
End Sub

另一种(更灵活的)解决方案是使用良好的旧一维线性存储概念(实际上系统存储阵列的方式),并计算实际入口的实际位置

谢谢-原则上是个好主意。不幸的是,在我的例子中,它确实需要以数组的形式出现——因为这是关于序列化/反序列化的,我确实需要准确地重新创建以前序列化的类型。在这种情况下,您必须竭尽全力,使用一组
case
-语句。我正在编写一个示例,但是@AcsErno的速度更快。我已经在下面回复了-也感谢您的输入!我可能会走那条路!谢谢希望有一些秘密的方法,例如创建一些安全阵列并将数据复制到其中;但对于Variant/String/etc.类型来说,这也会变得非常棘手。无论如何-将沿着这条路线前进,并将支撑限制在合理的尺寸范围内!感谢你的深思熟虑——我想我已经“原则上”解决了一般情况下的这个问题;例如,我可以创建一个一维数组,然后使用正确的SAFEARRAYBOUND元素创建一个新的SAFEARRAY标头,然后重新指向数组以使用它。但我必须研究内存管理,我不确定VBA如何处理这一问题,并担心这可能会泄漏(例如,不再有任何东西指向旧的SAFEARRAY结构-它会从内存中释放吗?)