动态地改变nr。 VBA数组的维度

时间:2018-05-27 09:18:44

标签: vba multidimensional-array dynamic dimensions

我想知道是否有办法改变数组的维数:

  1. 在VBA中,
  2. 取决于表示其的整数max_dim_bound 期望的尺寸。
  3. 允许维度的起始索引:E.G。 `array(4到5,3到6),其中3到6的数字是可变整数。

  4. *代码本身没有额外的工具

  5. *不导出代码。
  6. 要清楚,以下更改更改数组的维度nr(仅仅是每个相应维度中元素的起始结束索引):

    my_arr(3 to 5, 6 to 10) 
    'changed to:
    my_arr(4 to 8, 2 to 7)
    

    以下示例将成功更改nr。数组中的维度:

    my_arr(3 to 5, 6 to 10) 
    'changed to:
    my_arr(4 to 8, 2 to 7,42 to 29)
    

    这也是nr的变化。数组中的维度:

    my_arr(4 to 8, 2 to 7,42 to 29)
    'changed to:
    my_arr(3 to 5, 6 to 10) 
    

    到目前为止,我的尝试包括:

    Sub test_if_dynamically_can_set_dimensions()
        Dim changing_dimension() As Double
        Dim dimension_string_attempt_0 As String
        Dim dimension_string_attempt_1 As String
        Dim max_dim_bound As String
        Dim lower_element_boundary As Integer
        Dim upper_element_boundary As Integer
    
        upper_element_boundary = 2
        max_dim_bound = 4
    
        For dimen = 1 To max_dim_bound
            If dimen < max_dim_bound Then
                dimension_string_attempt_0 = dimension_string_attempt_0 & "1 To " & upper_element_boundary & ","
                MsgBox (dimension_string_attempt_0)
            Else
                dimension_string_attempt_0 = dimension_string_attempt_0 & "1 To " & upper_element_boundary
            End If
        Next dimen
        MsgBox (dimension_string_attempt_0)
        'ReDim changing_dimension(dimension_string_attempt_0) 'does not work because the "To" as expected in the array dimension is not a string but reserved word that assists in the operation of setting an array's dimension(s)
        'ReDim changing_dimension(1 & "To" & 3, 1 To 3, 1 To 3) 'does not work because the word "To" that is expected here in the array dimension is not a string but a reserved word that assists the operation of setting an array's dimension(s).
        'ReDim changing_dimension(1 To 3, 1 To 3, 1 To 3, 1 To 3)
    
        'attempt 1:
        For dimen = 1 To max_dim_bound
            If dimen < max_dim_bound Then
                dimension_string_attempt_1 = dimension_string_attempt_1 & upper_element_boundary & ","
                MsgBox (dimension_string_attempt_1)
            Else
                dimension_string_attempt_1 = dimension_string_attempt_1 & upper_element_boundary
            End If
        Next dimen
        MsgBox (dimension_string_attempt_1)
        ReDim changing_dimension(dimension_string_attempt_1) 'this does not change the nr of dimensions to 2, but just one dimension of "3" and "3" = "33" = 33 elements + the 0th element
        'changing_dimension(2, 1, 2, 1) = 4.5
        'MsgBox (changing_dimension(2, 1, 2, 1))
    End Sub
    

    *否则解决方案是:

    1. 导出模块的整个代码,并在维度的行中用准动态字符串dimension_string替换数组的静态红维。
    2. 删除当前模块
    3. 使用准动态字符串dimension_string导入新模块作为代码中的刷新静态重定向。
    4. 然而,这似乎令人费解,如果有人知道更简单的解决方案,我很好奇。

      请注意,这不是重复:Dynamically Dimensioning A VBA Array?尽管问题似乎意味着我在这里提出的问题,但问题的目的似乎是改变 nr。尺寸中的元素,而不是nr。尺寸。 (差异在this article by Microsoft中讨论。)

      为了尝试应用Uri Goren的答案,我分析了每一行,并查看了他们所做的事情,并评论了我背后的理解,以便我的理解得到改善或纠正。因为我不仅难以运行代码,而且还了解如何回答问题。这种尝试包括以下步骤:

      1. 右键单击代码文件夹 - &gt;插入 - &gt;类模块然后单击: 工具&gt;选项&gt; “标记:需要变量声明”如图所示 {00}在00:59。
      2. 接下来,我将课程模块重命名为here

      3. 接下来,我在类模块FlexibleArray中编写了以下代码:

        Option Explicit
        Dim A As New FlexibleArray
        Private keys() As Integer
        Private vals() As String
        Private i As Integer
        
        Public Sub Init(ByVal n As Integer)
           ReDim keys(n) 'changes the starting element index of array keys to 0 and index of last element to n
           ReDim vals(n) 'changes the starting element index of array keys to 0 and index of last element to n
           For i = 1 To n
                keys(i) = i 'fills the array keys as with integers from 1 to n
           Next i
        End Sub
        
        Public Function GetByKey(ByVal key As Integer) As String
           GetByKey = vals(Application.Match(key, keys, False))
           ' Application.Match("what you want to find as variant", "where you can find it as variant", defines the combination of match type required and accompanying output)
            'Source: https://msdn.microsoft.com/en-us/vba/excel-vba/articles/worksheetfunction-match-method-excel
            ' If match_type is 1, MATCH finds the largest value that is less than or equal to lookup_value. Lookup_array must be placed in ascending order: ...-2, -1, 0, 1, 2, ..., A-Z, FALSE, TRUE.
            ' If match_type is 0, MATCH finds the first value that is exactly equal to lookup_value. Lookup_array can be in any order.
            ' If match_type is -1, MATCH finds the smallest value that is greater than or equal to lookup_value. Lookup_array must be placed in descending order: TRUE, FALSE, Z-A, ...2, 1, 0, -1, -2, ..., and so on.
        
            'so with False as 3rd optional argument "-1" it finds the smallest value greater than or equal to the lookup variant, meaning:
            'the lowest value of keys that equals or is greater than key is entered into vals,
            'with keys as an array of 1 to n, it will return key, if n >= key. (if keys is initialized right before getbykey is called and is not changed inbetween.
        
           'vals becomes the number inside a string. So vals becomes the number key if key >= n.
        
        End Function
        
        Public Sub SetByKey(ByVal key As Integer, ByVal val As String)
           vals(Application.Match(key, keys, False)) = val
           'here string array vals(element index: key) becomes string val if key >=n (meaning if the element exists)
        
        
        End Sub
        
        Public Sub RenameKey(ByVal oldName As Integer, ByVal newName As Integer)
           keys(Application.Match(oldName, keys, False)) = newName
            'here keys element oldname becomes new name if it exists in keys.
        End Sub
        
      4. 然后我创建了一个新模块11并将下面的代码复制到其中,包括修改以尝试使代码正常工作。

        Option Explicit
        Sub use_class_module()
        Dim A As New FlexibleArray 'this dimensions object A but it is not set yet
        A.Init (3) 'calls the public sub "Init" in class module FlexibleArray, and passes integer n = 3.
        'A.SetByKey(1, "a") 'this means that Objecgt A. in class FlexibleArray  function SetByKey sets the private string array vals(1) in class Flexible Array becomes "a"
        'A.SetByKey(2, "b") 'this means that Objecgt A. in class FlexibleArray function SetByKey sets the private string array vals(2) in class Flexible Array becomes "b"
        'A.SetByKey(3, "c") 'this means that Object A. in class FlexibleArray function SetByKey sets the private string array vals(3) in class Flexible Array becomes "c"
        'A.RenameKey(3,5) 'This means that object A in class FlexibleArray keys element 3 becomes 5 so keys(3) = 5
        
        ' Would print the char "c"
        
        'to try to use the functions:
        'A.SetByKey(1, "a") = 4
        'MsgBox (keys("a"))
        'test = A.SetByKey(1, "a") 'this means that Objecgt A. in class FlexibleArray  function SetByKey sets the private string array vals(1) in class Flexible Array becomes "a"
        'MsgBox (test)
        'test_rename = A.RenameKey(3, 5) 'This means that object A in class FlexibleArray keys element 3 becomes 5 so keys(3) = 5
        'MsgBox (test_rename)
        'Print A.GetByKey(5) 'Method not valid without suitable object
        
        
        'current problem:
        'the A.SetByKey expects a function or variable, even though it appears to be a function itself.
        
        End Sub
        
      5. 我目前期望此代码将my_array(3到4,5到9 ..)替换为/作为类模块FlexibleArray中存在的数组,该模块在需要在模块中使用时调用。但任何清晰度将不胜感激! :)

2 个答案:

答案 0 :(得分:1)

听起来你正在滥用数组,因为他们并不打算用大量的内存复制。

你想要的是自己编写Class(右击代码文件夹 - &gt;插入 - &gt;类模块),我们称之为FlexibleArray

您的班级代码将是这样的:

Private keys() as Integer
Private vals() as String
Private i as Integer

Public Sub Init(ByVal n as Integer)
   Redim keys(n)
   Redim vals(n)
   For i = 1 to n
        keys(i) = i
   Next i
End Sub

Public Function GetByKey(ByVal key As Integer) As String
   GetByKey = vals(Application.Match(key, keys, False))
End Function

Public Sub SetByKey(ByVal key As Integer, ByVal val As String)
   vals(Application.Match(key, keys, False)) = val
End Sub

Public Sub RenameKey(ByVal oldName As Integer, ByVal newName As Integer)
   keys(Application.Match(oldName, keys, False))=newName
End Sub

现在你可以重命名你想要的任何键:

Dim A as New FlexibleArray
A.Init(3)
A.SetByKey(1, "a")
A.SetByKey(2, "b")
A.SetByKey(3, "c")
A.RenameKey(3,5)
Print A.GetByKey(5)
' Would print the char "c"

将它扩展到整数范围(就像你的例子)非常简单

答案 1 :(得分:1)

如果重新定义数组的目标仅限于非荒谬的数量级别,那么一个简单的函数可能对您有用,比如1到4维吗?

你可以传递一个表示每个维度的下边界和上边界的字符串,然后传回重新标注的数组

Public Function FlexibleArray(strDimensions As String) As Variant

    ' strDimensions = numeric dimensions of new array
    ' eg. "1,5,3,6,2,10" creates ARRAY(1 To 5, 3 To 6, 2 To 10)

    Dim arr()               As Variant
    Dim varDim              As Variant
    Dim intDim              As Integer

    varDim = Split(strDimensions, ",")
    intDim = (UBound(varDim) + 1) / 2

    Select Case intDim
        Case 1
            ReDim arr(varDim(0) To varDim(1))
        Case 2
            ReDim arr(varDim(0) To varDim(1), varDim(2) To varDim(3))
        Case 3
            ReDim arr(varDim(0) To varDim(1), varDim(2) To varDim(3), varDim(4) To varDim(5))
        Case 4
            ReDim arr(varDim(0) To varDim(1), varDim(2) To varDim(3), varDim(4) To varDim(5), varDim(6) To varDim(7))
    End Select

    ' Return re-dimensioned array
    FlexibleArray = arr
End Function

通过使用数组边界调用

来测试它
Public Sub redimarray()
    Dim NewArray() As Variant

    NewArray = FlexibleArray("1,2,3,8,2,9")
End Sub

应该在调试模式下返回一个类似的数组 watch value

编辑 - 添加了真正动态变量数组的示例

以下是获得真正灵活的重新定义数组的方法示例,但我不确定它是什么,因为firt索引用于访问其他数组元素。

Public Function FlexArray(strDimensions As String) As Variant

    Dim arrTemp     As Variant
    Dim varTemp     As Variant

    Dim varDim      As Variant
    Dim intNumDim   As Integer

    Dim iDim        As Integer
    Dim iArr        As Integer

    varDim = Split(strDimensions, ",")
    intNumDim = (UBound(varDim) + 1) / 2

    ' Setup redimensioned source array
    ReDim arrTemp(intNumDim)

    iArr = 0
    For iDim = LBound(varDim) To UBound(varDim) Step 2

        ReDim varTemp(varDim(iDim) To varDim(iDim + 1))
        arrTemp(iArr) = varTemp
        iArr = iArr + 1
    Next iDim

    FlexArray = arrTemp
End Function

如果你在Debug中查看它,你会注意到现在可以从返回数组的第一个索引访问的重新定义的子数组

FlexArray output