ReDim Preserve to a Multi-Dimensional Array in Visual Basic 6

前端 未结 10 390
孤城傲影
孤城傲影 2020-11-29 09:44

I\'m using VB6 and I need to do a ReDim Preserve to a Multi-Dimensional Array:

 Dim n, m As Integer
    n = 1
    m = 0
    Dim arrCity() As String
    ReDi         


        
相关标签:
10条回答
  • 2020-11-29 09:51

    I stumbled across this question while hitting this road block myself. I ended up writing a piece of code real quick to handle this ReDim Preserve on a new sized array (first or last dimension). Maybe it will help others who face the same issue.

    So for the usage, lets say you have your array originally set as MyArray(3,5), and you want to make the dimensions (first too!) larger, lets just say to MyArray(10,20). You would be used to doing something like this right?

     ReDim Preserve MyArray(10,20) '<-- Returns Error
    

    But unfortunately that returns an error because you tried to change the size of the first dimension. So with my function, you would just do something like this instead:

     MyArray = ReDimPreserve(MyArray,10,20)
    

    Now the array is larger, and the data is preserved. Your ReDim Preserve for a Multi-Dimension array is complete. :)

    And last but not least, the miraculous function: ReDimPreserve()

    'redim preserve both dimensions for a multidimension array *ONLY
    Public Function ReDimPreserve(aArrayToPreserve,nNewFirstUBound,nNewLastUBound)
        ReDimPreserve = False
        'check if its in array first
        If IsArray(aArrayToPreserve) Then       
            'create new array
            ReDim aPreservedArray(nNewFirstUBound,nNewLastUBound)
            'get old lBound/uBound
            nOldFirstUBound = uBound(aArrayToPreserve,1)
            nOldLastUBound = uBound(aArrayToPreserve,2)         
            'loop through first
            For nFirst = lBound(aArrayToPreserve,1) to nNewFirstUBound
                For nLast = lBound(aArrayToPreserve,2) to nNewLastUBound
                    'if its in range, then append to new array the same way
                    If nOldFirstUBound >= nFirst And nOldLastUBound >= nLast Then
                        aPreservedArray(nFirst,nLast) = aArrayToPreserve(nFirst,nLast)
                    End If
                Next
            Next            
            'return the array redimmed
            If IsArray(aPreservedArray) Then ReDimPreserve = aPreservedArray
        End If
    End Function
    

    I wrote this in like 20 minutes, so there's no guarantees. But if you would like to use or extend it, feel free. I would've thought that someone would've had some code like this up here already, well apparently not. So here ya go fellow gearheads.

    0 讨论(0)
  • 2020-11-29 09:52

    Since VB6 is very similar to VBA, I think I might have a solution which does not require this much code to ReDim a 2-dimensional array - using Transpose, if you are working in Excel.

    The solution (Excel VBA):

    Dim n, m As Integer
    n = 2
    m = 1
    Dim arrCity() As Variant
    ReDim arrCity(1 To n, 1 To m)
    
    m = m + 1
    ReDim Preserve arrCity(1 To n, 1 To m)
    arrCity = Application.Transpose(arrCity)
    n = n + 1
    ReDim Preserve arrCity(1 To m, 1 To n)
    arrCity = Application.Transpose(arrCity)
    

    What is different from OP's question: the lower bound of arrCity array is not 0, but 1. This is in order to let Application.Transpose do it's job.

    Note that Transpose is a method of the Excel Application object (which in actuality is a shortcut to Application.WorksheetFunction.Transpose). And in VBA, one must take care when using Transpose as it has two significant limitations: If the array has more than 65536 elements, it will fail. If ANY element's length exceed 256 characters, it will fail. If neither of these is an issue, then Transpose will nicely convert the rank of an array form 1D to 2D or vice-versa.

    Unfortunately there is nothing like 'Transpose' build into VB6.

    0 讨论(0)
  • 2020-11-29 09:54

    I know this is a bit old but I think there might be a much simpler solution that requires no additional coding:

    Instead of transposing, redimming and transposing again, and if we talk about a two dimensional array, why not just store the values transposed to begin with. In that case redim preserve actually increases the right (second) dimension from the start. Or in other words, to visualise it, why not store in two rows instead of two columns if only the nr of columns can be increased with redim preserve.

    the indexes would than be 00-01, 01-11, 02-12, 03-13, 04-14, 05-15 ... 0 25-1 25 etcetera instead of 00-01, 10-11, 20-21, 30-31, 40-41 etcetera.

    As long as there is only one dimension that needs to be redimmed-preserved the approach would still work: just put that dimension last.

    As only the second (or last) dimension can be preserved while redimming, one could maybe argue that this is how arrays are supposed to be used to begin with. I have not seen this solution anywhere so maybe I'm overlooking something?

    (Posted earlier on similar question regarding two dimensions, extended answer here for more dimensions)

    0 讨论(0)
  • 2020-11-29 10:00

    You can use a user defined type containing an array of strings which will be the inner array. Then you can use an array of this user defined type as your outer array.

    Have a look at the following test project:

    '1 form with:
    '  command button: name=Command1
    '  command button: name=Command2
    Option Explicit
    
    Private Type MyArray
      strInner() As String
    End Type
    
    Private mudtOuter() As MyArray
    
    Private Sub Command1_Click()
      'change the dimensens of the outer array, and fill the extra elements with "1"
      Dim intOuter As Integer
      Dim intInner As Integer
      Dim intOldOuter As Integer
      intOldOuter = UBound(mudtOuter)
      ReDim Preserve mudtOuter(intOldOuter + 2) As MyArray
      For intOuter = intOldOuter + 1 To UBound(mudtOuter)
        ReDim mudtOuter(intOuter).strInner(intOuter) As String
        For intInner = 0 To UBound(mudtOuter(intOuter).strInner)
          mudtOuter(intOuter).strInner(intInner) = "1"
        Next intInner
      Next intOuter
    End Sub
    
    Private Sub Command2_Click()
      'change the dimensions of the middle inner array, and fill the extra elements with "2"
      Dim intOuter As Integer
      Dim intInner As Integer
      Dim intOldInner As Integer
      intOuter = UBound(mudtOuter) / 2
      intOldInner = UBound(mudtOuter(intOuter).strInner)
      ReDim Preserve mudtOuter(intOuter).strInner(intOldInner + 5) As String
      For intInner = intOldInner + 1 To UBound(mudtOuter(intOuter).strInner)
        mudtOuter(intOuter).strInner(intInner) = "2"
      Next intInner
    End Sub
    
    Private Sub Form_Click()
      'clear the form and print the outer,inner arrays
      Dim intOuter As Integer
      Dim intInner As Integer
      Cls
      For intOuter = 0 To UBound(mudtOuter)
        For intInner = 0 To UBound(mudtOuter(intOuter).strInner)
          Print CStr(intOuter) & "," & CStr(intInner) & " = " & mudtOuter(intOuter).strInner(intInner)
        Next intInner
        Print "" 'add an empty line between the outer array elements
      Next intOuter
    End Sub
    
    Private Sub Form_Load()
      'init the arrays
      Dim intOuter As Integer
      Dim intInner As Integer
      ReDim mudtOuter(5) As MyArray
      For intOuter = 0 To UBound(mudtOuter)
        ReDim mudtOuter(intOuter).strInner(intOuter) As String
        For intInner = 0 To UBound(mudtOuter(intOuter).strInner)
          mudtOuter(intOuter).strInner(intInner) = CStr((intOuter + 1) * (intInner + 1))
        Next intInner
      Next intOuter
      WindowState = vbMaximized
    End Sub
    

    Run the project, and click on the form to display the contents of the arrays.

    Click on Command1 to enlarge the outer array, and click on the form again to show the results.

    Click on Command2 to enlarge an inner array, and click on the form again to show the results.

    Be careful though: when you redim the outer array, you also have to redim the inner arrays for all the new elements of the outer array

    0 讨论(0)
  • 2020-11-29 10:00

    This is more compact and respect the intial first position in array and just use the inital bound to add old value.

    Public Sub ReDimPreserve(ByRef arr, ByVal size1 As Long, ByVal size2 As Long)
    Dim arr2 As Variant
    Dim x As Long, y As Long
    
    'Check if it's an array first
    If Not IsArray(arr) Then Exit Sub
    
    'create new array with initial start
    ReDim arr2(LBound(arr, 1) To size1, LBound(arr, 2) To size2)
    
    'loop through first
    For x = LBound(arr, 1) To UBound(arr, 1)
        For y = LBound(arr, 2) To UBound(arr, 2)
            'if its in range, then append to new array the same way
            arr2(x, y) = arr(x, y)
        Next
    Next
    'return byref
    arr = arr2
    End Sub
    

    I call this sub with this line to resize the first dimension

    ReDimPreserve arr2, UBound(arr2, 1) + 1, UBound(arr2, 2)
    

    You can add an other test to verify if the initial size is not upper than new array. In my case it's not necessary

    0 讨论(0)
  • 2020-11-29 10:03

    As you correctly point out, one can ReDim Preserve only the last dimension of an array (ReDim Statement on MSDN):

    If you use the Preserve keyword, you can resize only the last array dimension and you can't change the number of dimensions at all. For example, if your array has only one dimension, you can resize that dimension because it is the last and only dimension. However, if your array has two or more dimensions, you can change the size of only the last dimension and still preserve the contents of the array

    Hence, the first issue to decide is whether 2-dimensional array is the best data structure for the job. Maybe, 1-dimensional array is a better fit as you need to do ReDim Preserve?

    Another way is to use jagged array as per Pieter Geerkens's suggestion. There is no direct support for jagged arrays in VB6. One way to code "array of arrays" in VB6 is to declare an array of Variant and make each element an array of desired type (String in your case). Demo code is below.

    Yet another option is to implement Preserve part on your own. For that you'll need to create a copy of data to be preserved and then fill redimensioned array with it.

    Option Explicit
    
    Public Sub TestMatrixResize()
        Const MAX_D1 As Long = 2
        Const MAX_D2 As Long = 3
    
        Dim arr() As Variant
        InitMatrix arr, MAX_D1, MAX_D2
        PrintMatrix "Original array:", arr
    
        ResizeMatrix arr, MAX_D1 + 1, MAX_D2 + 1
        PrintMatrix "Resized array:", arr
    End Sub
    
    Private Sub InitMatrix(a() As Variant, n As Long, m As Long)
        Dim i As Long, j As Long
        Dim StringArray() As String
    
        ReDim a(n)
        For i = 0 To n
            ReDim StringArray(m)
            For j = 0 To m
                StringArray(j) = i * (m + 1) + j
            Next j
            a(i) = StringArray
        Next i
    End Sub
    
    Private Sub PrintMatrix(heading As String, a() As Variant)
        Dim i As Long, j As Long
        Dim s As String
    
        Debug.Print heading
        For i = 0 To UBound(a)
            s = ""
            For j = 0 To UBound(a(i))
                s = s & a(i)(j) & "; "
            Next j
            Debug.Print s
        Next i
    End Sub
    
    Private Sub ResizeMatrix(a() As Variant, n As Long, m As Long)
        Dim i As Long
        Dim StringArray() As String
    
        ReDim Preserve a(n)
        For i = 0 To n - 1
            StringArray = a(i)
            ReDim Preserve StringArray(m)
            a(i) = StringArray
        Next i
        ReDim StringArray(m)
        a(n) = StringArray
    End Sub
    
    0 讨论(0)
提交回复
热议问题