2010-10-21 13 views
8

Estoy trabajando con una matriz dinámica en Excel VBA. El número de columnas (m) es fijo, sin embargo, no sé cuántas filas (n) se requerirán.¿Cómo puedo "ReDim Preserve" una matriz 2D en Excel 2007 VBA para poder agregar filas, no columnas, a la matriz?

Los documentos de ayuda indican que ReDim Preserve myArray (n, m) me permite hacer m más grande, pero no n. Sin embargo, necesito aumentar el número de filas (n) mientras conservo mis datos, ¡no las columnas (m)!

Por ejemplo, puedo tener una matriz (5,20) en la que me gustaría expandirme (10,20) mientras guardo mis datos.

Parece que si hubiera alguna manera de transponer mi matriz, haga una ReDim Preserve para expandir el número de "columnas", luego vuelva a transponer mi matriz, podría lograr lo que quiero.

¿Es esta la forma correcta de hacerlo? Si es así, ¿cómo puedo hacer eso?

¿Hay una mejor manera de lograr lo que quiero?

Respuesta

0

Resolvió mi propia pregunta; Así es como resolví mi problema. Creé una matriz temporal, copié el contenido de myArray a la matriz temporal, cambié el tamaño de myArray y luego copié los contenidos desde la matriz temporal a myArray.

tempArray = myArray 
ReDim myArray(1 To (UBound(myArray()) * 2), 1 To m) 
For i = 1 To n 
    For j = 1 To m 
      myArray(i, j) = tempArray(i, j) 
    Next j 
Next i 

Si alguien puede sugerir una forma más eficiente de hacer esto, me encantaría escucharlo.

+2

-1: Dos ciclos anidados para cada redim de una matriz - no es una idea brillante en todo! ¿Qué va a pasar si tienes una matriz de 10 000 elementos? –

0

¿No hay forma de determinar el número de elementos en la primera dimensión? Gorrón. Para una matriz bidimensional con una segunda dimensión fija, es posible que desee considerar convertirla en una matriz de Tipos ("estructuras" en otros idiomas). Esto le permitirá usar Redim Preserve y todavía le deja una forma razonable de agregar y acceder a valores, aunque ahora tendrá acceso a la segunda dimensión como miembros con nombre del Tipo en lugar de valores de índice.

12

Una forma de hacer lo que desea es utilizar una matriz 1-D que contenga matrices 1-D en lugar de una matriz 2-D. Entonces puedes ReDim Preservar la matriz externa todo lo que quieras. Si devuelve la matriz externa desde una función, Excel hará lo correcto y lo forzará a una matriz 2-D.

Por ejemplo, la siguiente función devolverá una matriz de 3x2 a las células que se llama a partir de:

Public Function nested() 
    Dim outer 
    outer = Array(Array(1, 2), Array(3, 4)) 

    ReDim Preserve outer(1 To 3) 

    outer(3) = Array(5, 6) 

    nested = outer 
End Function 

Mi respuesta a estas preguntas también podría ser útil para usted: Pass multidimensional array into Excel UDF in VBA y VBA pasting 3 dimensional array into sheet

Por supuesto , si no devuelve esto desde un UDF, tendrá que forzarlo usted mismo. Una manera fácil de hacerlo sin necesidad de escribir código de bucle es hacer esto:

Dim coerced 
coerced = Application.Index(outer, 0, 0) 

Esto es sólo el llamado de Excel función integrada de índice y los ceros significan que desea volver todas sus filas y todas las columnas . Excel forzará automáticamente su matriz 1-D de matrices 1-D a una matriz 2-D. (Advertencia: hay algunas limitaciones de tamaño, pero son mucho más grandes que 10x20.)

+0

No terminé usando o probando esto porque mi solución fue lo suficientemente buena para mis necesidades esta vez. A primera vista, parece una forma más elegante y eficiente de hacer lo que quería. – user392520

2

La palabra 'transponer' inmediatamente me viene a la mente. Simplemente puede ingresar datos en la matriz 2D volteando las columnas y las filas (es decir, transponer), lo que le permite hacer que n (ahora el número de columnas, pero almacenando los valores de la fila) sea más grande cuando lo necesite.

Para hacer referencia a los valores, por ejemplo, en un bucle doble, intercambie los índices.P.ej. en lugar de ir de i = 1 a n y j = 1 a m donde el valor de referencia (i, j), use i = 1 a m y j = 1 a n.

5

Si es desarrollador, ¿cuál es la diferencia entre filas y columnas? Usando array (N, 2) (si tiene 2 columnas) es el mismo que array (2, N) - para el que puede

ReDim Preserve arr(1 to 2, 1 to N+1). 

Y la diferencia para usted (como desarrollador) será poner la variable del ciclo en el segundo lugar, en vez de la primera:

N = ubound(arr) 
FOR i=1 to N 
    GetColumn1Value = arr(1, i) 
    GetColumn2Value = arr(2, i) 
NEXT i 

o si desea esto:

N = ubound(arr) 
FOR i=1 to N 
    GetColumn1Value = arr(i, 1) 
    GetColumn2Value = arr(i, 2) 
NEXT i 

¿Cuál es la diferencia?

+0

Bueno, la diferencia es que podría necesitar cambiar AMBAS dimensiones. O no sé qué dimensión se verá afectada. – Ister

+0

@Ister, si utiliza 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. https://msdn.microsoft.com/en-us/library/office/gg251578.aspx La regla es válida no solo para Office 2013 y posterior, como en el enlace anterior, sino para cualquier Office a partir de 2003 (I no tengo experiencia con versiones anteriores). –

+0

Soy plenamente consciente de esa limitación. Lo que quiero decir es que no puedo simplemente transponer la matriz cada vez o ser feliz con la posibilidad de cambiar solo el tamaño de la última dimensión. – Ister

4

Una forma de cómo se puede realmente es una doble transposición con un cambio en el número de columnas intermedias. Sin embargo, esto solo funcionará para arreglos bidimensionales. Se realiza de la siguiente manera:

' Adding one row is done by a double transposing and adding a column in between. 
' (Excel VBA does not allow to change the size of the non-last dimension of a 
' multidimensional array.) 
myArray = Application.Transpose(myArray) 
ReDim Preserve myArray(1 To m, 1 To n + 1) 
myArray= Application.Transpose(myArray) 

Por supuesto m y n se puede deducir de la siguiente manera:

m = UBound(myArray, 1) 
n = UBound(myArray, 2) 

por lo que utilizar la funcionalidad de transposición integrado de Excel sí mismo. Como se menciona en los comentarios del código, esto no funcionará para matrices de orden superior.

+0

Gracias. Me sorprende lo rápido que es esto. 0.08sek para 16200 filas * 14 columnas = 226000 valores (2x transposición, 1x redim) –

0

coercing o Slicing no parece funcionar con Index (o Match (Índice (cuando quiero filtrar array (sin bucles) basado en múltiples criterios, cuando el tamaño de los datos abarca más de 2^16 filas (~ 92000 filas).

Run-Time error '13': 

Type Mismatch 

transposición no trabaja con grandes conjuntos de registros y por lo tanto también el doble de transposición no funciona. no hay alguna forma de filtrar una serie de datos y de agarre sin tener que recurrir a múltiples bucles?

soy pensando en probar el modo de diccionario o ADO con Excel.

0

Una matriz con 2 dimensiones, donde el número de columnas son fijos y el número de filas son dinámicos, se puede crear como este:

Sub test2DimArray() 
Dim Arr2D() As String 
Dim NumberOfCol As Long 
Dim I As Long, J As Long, x As Long 
Dim tmpValue As String, tmpValue2 As String, tmpValue3 As String 

NumberOfCol = 3 
J = 1 
Debug.Print "Run " & Now() 
Debug.Print "Sheet content" 
Debug.Print "Row col1  col2  col3" 

For I = 1 To 10 
tmpValue = Cells(I, 1).Value 
tmpValue2 = Cells(I, 2).Value 
tmpValue3 = Cells(I, 3).Value 
Debug.Print I & " = " & tmpValue & "  " & tmpValue2 & "  " & tmpValue3 
    If Len(tmpValue) > 0 Then 
     ReDim Preserve Arr2D(NumberOfCol, 1 To J) 
     Arr2D(1, J) = tmpValue 
     Arr2D(2, J) = tmpValue2 
     Arr2D(3, J) = tmpValue3 
     J = J + 1 
    End If 
Next 

'check array values 
Debug.Print vbLf; "arr2d content" 
Debug.Print "Row col1  col2  col3" 

For x = LBound(Arr2D, 2) To UBound(Arr2D, 2) 
Debug.Print x & " = " & Arr2D(1, x) & "  " & Arr2D(2, x) & "  " & Arr2D(3, x) 
Next 

Debug.Print "=========================" 
End Sub 

TempValue leer a partir de células A1: A10, si hay un valor de la celda Axe, redimirá la matriz con +1, y agregará Tempvalue a la matriz col1, agregará contenidos en Bx a la matriz col2 y contenidos en Cx a la matriz col3. Si la longitud del valor Ax es 0, no agrega nada a la matriz.

Debug.print muestra los resultados en la "ventana inmediata" en el editor de VB.

sin las líneas de prueba, y la adición de una técnica de gama dinámica el código puede ser:

Sub my2DimArray() 
Dim Arr2D() As String 
Dim NumberOfCol As Long, NumberOfRow As Long 
Dim FirstCol As Long, FirstRow As Long, LastCol As Long, LastRow As Long 
Dim I As Long, J As Long, X As Long 
Dim tmpValue As String, tmpValue2 As String, tmpValue3 As String 

'if cells with values start in A1 
With ActiveSheet.UsedRange 
    NumberOfCol = .Columns.Count 
    NumberOfRow = .Rows.Count 
End With 

'if cells with values starts elsewhere 
With ActiveSheet.UsedRange 
    FirstCol = .Column 
    FirstRow = .Row 
    LastCol = .Column + .Columns.Count - 1 
    LastRow = .Row + .Rows.Count - 1 
End With 

J = 1 

For I = 1 To NumberOfRow 'or For I = FirstRow to LastRow 
tmpValue = Cells(I, 1).Value 'or tmpValue = Cells(I, FirstCol).Value 
    If Len(tmpValue) > 0 Then 
     ReDim Preserve Arr2D(NumberOfCol, 1 To J) 
      For X = 1 To NumberOfCol 'or For X = FirstCol to LastCol 
       Arr2D(X, J) = Cells(I, X).Value 
      Next X 
     J = J + 1 
    End If 
Next I 

End Sub 
Cuestiones relacionadas