ReDim Preserve a una matriz multidimensional en Visual Basic 6

Estoy usando VB6 y necesito hacer una ReDim Preserve en una matriz multidimensional:

Dim n, m As Integer n = 1 m = 0 Dim arrCity() As String ReDim arrCity(n, m) n = n + 1 m = m + 1 ReDim Preserve arrCity(n, m) 

Cada vez que lo hago como lo escribí, recibo el siguiente error:

error de tiempo de ejecución 9: subíndice fuera de rango

Como solo puedo cambiar la última dimensión de la matriz, en mi tarea, tengo que cambiar toda la matriz (¡2 dimensiones en mi ejemplo)!

¿Hay alguna solución u otra solución para esto?

Como señala correctamente, uno puede ReDim Preserve solo la última dimensión de una matriz ( ReDim Statement en MSDN):

Si usa la palabra clave Preserve, puede cambiar el tamaño solo de la última dimensión de matriz y no puede cambiar el número de dimensiones. Por ejemplo, si su matriz tiene solo una dimensión, puede cambiar el tamaño de esa dimensión porque es la última y única dimensión. Sin embargo, si su matriz tiene dos o más dimensiones, puede cambiar el tamaño de la última dimensión y conservar el contenido de la matriz.

Por lo tanto, el primer problema para decidir es si la matriz bidimensional es la mejor estructura de datos para el trabajo. Tal vez, una matriz de 1 dimensión es una mejor opción ya que debes hacer ReDim Preserve .

Otra forma es usar una matriz irregular según la sugerencia de Pieter Geerkens . No hay soporte directo para arreglos dentados en VB6. Una forma de codificar “array of arrays” en VB6 es declarar una matriz de Variant y hacer que cada elemento sea una matriz del tipo deseado ( String en su caso). El código de demostración está debajo.

Otra opción más es implementar la parte Preserve por su cuenta. Para eso, necesitará crear una copia de datos para preservar y luego completar la matriz redimensionada con ella.

 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 

Dado que VB6 es muy similar a VBA, creo que podría tener una solución que no requiera tanto código para ReDim una matriz bidimensional, utilizando Transpose .

La solución (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) 

Lo que es diferente de la pregunta de OP: el límite inferior de la matriz arrCity no es 0, sino 1. Esto es para permitir que Application.Transpose haga su trabajo.

Creo que deberías tener el método Transpose en VB6.

Con respecto a esto:

“en mi tarea tengo que cambiar toda la matriz (2 dimensiones)

Solo use una matriz dentada (es decir, una matriz de matrices de valores). Entonces puedes cambiar las dimensiones como lo desees. Quizás un poco más de trabajo, pero una solución.

No he probado todas estas respuestas, pero no necesita usar funciones complicadas para lograr esto. ¡Es mucho más fácil que eso! Mi código a continuación funcionará en cualquier aplicación de Office VBA (Word, Access, Excel, Outlook, etc.) y es muy simple. Espero que esto ayude:

 ''Dimension 2 Arrays Dim InnerArray(1 To 3) As Variant ''The inner is for storing each column value of the current row Dim OuterArray() As Variant ''The outer is for storing each row in Dim i As Byte i = 1 Do While i <= 5 ''Enlarging our outer array to store a/another row ReDim Preserve OuterArray(1 To i) ''Loading the current row column data in InnerArray(1) = "My First Column in Row " & i InnerArray(2) = "My Second Column in Row " & i InnerArray(3) = "My Third Column in Row " & i ''Loading the entire row into our array OuterArray(i) = InnerArray i = i + 1 Loop ''Example print out of the array to the Intermediate Window Debug.Print OuterArray(1)(1) Debug.Print OuterArray(1)(2) Debug.Print OuterArray(2)(1) Debug.Print OuterArray(2)(2) 

Puede usar un tipo definido por el usuario que contenga una matriz de cadenas que será la matriz interna. Luego puede usar una matriz de este tipo definido por el usuario como su matriz externa.

Echa un vistazo al siguiente proyecto de prueba:

 '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 

Ejecute el proyecto y haga clic en el formulario para mostrar el contenido de las matrices.

Haga clic en Command1 para agrandar la matriz externa y vuelva a hacer clic en el formulario para mostrar los resultados.

Haga clic en Command2 para agrandar una matriz interna y vuelva a hacer clic en el formulario para mostrar los resultados.

Sin embargo, ten cuidado: cuando redimieres la matriz externa, también tienes que redirigir las matrices internas para todos los elementos nuevos de la matriz externa

Me encontré con esta pregunta mientras golpeaba este bloque de carreteras yo mismo. Terminé escribiendo un fragmento de código muy rápido para manejar esta ReDim Preserve en una nueva matriz de tamaño (primera o última dimensión). Tal vez ayudará a otros que enfrentan el mismo problema.

Por lo tanto, para el uso, digamos que tiene su matriz originalmente configurada como MyArray(3,5) , y desea hacer que las dimensiones (¡también en primer lugar!) MyArray(10,20) más grandes, digamos a MyArray(10,20) . Estarías acostumbrado a hacer algo así ¿no?

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

Pero desafortunadamente eso devuelve un error porque trataste de cambiar el tamaño de la primera dimensión. Entonces con mi función, simplemente harías algo como esto:

  MyArray = ReDimPreserve(MyArray,10,20) 

Ahora la matriz es más grande y los datos se conservan. Su ReDim Preserve para una matriz Multi-Dimension está completa. 🙂

Y por último pero no menos importante, la función milagrosa: 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 

Lo escribí en 20 minutos, así que no hay garantías. Pero si desea usarlo o ampliarlo, siéntase libre. Pensé que alguien ya tendría aquí un código como este, bueno, aparentemente no. Así que aquí ya van compañeros gearheads.

Esto es más compacto y respeta la primera posición inicial en el conjunto y simplemente usa el límite inicial para agregar un valor anterior.

 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 

Llamo a este sub con esta línea para cambiar el tamaño de la primera dimensión

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

Puede agregar otra prueba para verificar si el tamaño inicial no es superior a la nueva matriz. En mi caso no es necesario

Sé que esto es un poco antiguo, pero creo que podría haber una solución mucho más simple que no requiere encoding adicional:

En lugar de transponer, enrojecer y transponer de nuevo, y si hablamos de una matriz bidimensional, ¿por qué no simplemente almacenar los valores transpuestos para empezar? En ese caso, redim preserve realmente aumenta la dimensión derecha (segunda) desde el comienzo. O en otras palabras, para visualizarlo, ¿por qué no almacenar en dos filas en lugar de dos columnas si solo el nr de columnas se puede boost con redim preserve?

los índices podrían ser 00-01, 01-11, 02-12, 03-13, 04-14, 05-15 … 0 25-1 25 etcétera en lugar de 00-01, 10-11, 20-21 , 30-31, 40-41, etcétera.

Mientras haya una sola dimensión que necesite ser redimidada, preservada, el enfoque seguirá funcionando: simplemente ponga esa dimensión al final.

Como solo se puede preservar la segunda (o última) dimensión mientras se está enrojeciendo, se podría argumentar que así es como se supone que se deben usar las matrices para empezar. No he visto esta solución en ningún lado así que tal vez estoy pasando por alto algo?

(Publicado anteriormente en una pregunta similar sobre dos dimensiones, respuesta extendida aquí para más dimensiones)