Excel 编译时维度未知时创建和填充数组
我正在研究通过VBA进行二进制序列化和反序列化 为此,我需要能够动态地创建和填充任意数量的维度数组。例如,假设您想做以下事情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
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结构-它会从内存中释放吗?)