Crear una matriz a partir de un rango en VBA
Tengo un problema aparentemente básico pero no encuentro ningún recurso para solucionarlo.
En pocas palabras, solo quiero cargar el contenido de un rango de celdas (todas una columna) en una matriz.
Puedo lograr esto por medio de
DirArray = Array(Range("A1"), Range("A2"))
Pero por alguna razón, no puedo crear la matriz cuando se expresa de esta manera:
DirArray = Array(Range("A1:A2"))
Mi rango real es mucho más largo (y puede variar en longitud), por lo que no quiero tener que enumerar las celdas individualmente de esta manera. ¿Alguien puede decirme cómo cargar correctamente un rango completo en una matriz?
Con el último código:
MsgBox UBound(DirArray, 1)
Y
MsgBox UBound(DirArray)
Devuelve 0, mientras que con el primero devuelve 1.
Simplemente defina la variable como una variante y hágalas iguales:
Dim DirArray As Variant
DirArray = Range("a1:a5").Value
No es necesario el comando Array.
Si lo hacemos así:
Dim myArr as Variant
myArr = Range("A1:A10")
la nueva matriz tendrá dos dimensiones. Con lo cual no siempre es cómodo trabajar:
Para alejarnos de las dos dimensiones, al convertir una sola columna en una matriz, podemos usar la función incorporada de Excel "Transponer". Con él, los datos pasan a tener una dimensión:
Si tenemos los datos en una fila, una sola transposición no funcionará. Necesitamos usar la función Transponer dos veces:
Nota: Como puede ver en las capturas de pantalla, cuando se generan de esta manera, las matrices comienzan con 1, no con 0. Solo tenga un poco de cuidado.
Edición de junio de 2021:
en versiones más nuevas de Excel, la función es:Application.WorksheetFunction.Transpose()
Edición de febrero de 2024: hice un video de YouTube que lo explica: https://www.youtube.com/watch?v=cGKUdKCSQxk
El uso Value2
proporciona un beneficio de rendimiento. Según el blog de Charles Williams
Range.Value2 funciona de la misma manera que Range.Value, excepto que no verifica el formato de la celda y lo convierte a Fecha o Moneda. Y probablemente por eso es más rápido que .Value al recuperar números.
Entonces
DirArray = [a1:a5].Value2
Lectura adicional
- Range.Value : Devuelve o establece un valor de variante que representa el valor del rango especificado.
- Range.Value2 : la única diferencia entre esta propiedad y la propiedad Value es que la propiedad Value2 no utiliza los tipos de datos Moneda y Fecha.
Además de las soluciones propuestas, y en caso de que tenga un rango 1D a una matriz 1D, prefiero procesarlo mediante una función como la siguiente. La razón es simple: si por alguna razón su rango se reduce a 1 elemento, hasta donde yo sé, el comando Rango().Valor no devolverá una matriz variante sino solo una variante y no podrá asignar una variante. variable a una matriz variante (previamente declarada).
Tuve que convertir un rango de tamaño variable en una matriz doble, y cuando el rango era de 1 tamaño de celda, no pude usar una construcción como range().value, así que procedo con una función como la siguiente.
Public Function Rng2Array(inputRange As Range) As Double()
Dim out() As Double
ReDim out(inputRange.Columns.Count - 1)
Dim cell As Range
Dim i As Long
For i = 0 To inputRange.Columns.Count - 1
out(i) = inputRange(1, i + 1) 'loop over a range "row"
Next
Rng2Array = out
End Function
Esta función devuelve una matriz independientemente del tamaño del rango.
Los rangos devolverán una matriz a menos que el rango sea solo de 1 celda y luego devuelva un valor único. Esta función convertirá el valor único en una matriz (basada en 1, igual que la matriz devuelta por rangos)
Esta respuesta mejora las respuestas anteriores, ya que devolverá una matriz de un rango sin importar el tamaño. También es más eficiente que otras respuestas, ya que, si es posible, devolverá la matriz generada por el rango. Funciona con matrices unidimensionales y multidimensionales.
La función funciona intentando encontrar los límites superiores de la matriz. Si eso falla, entonces debe ser un valor único, por lo que crearemos una matriz y le asignaremos el valor.
Public Function RangeToArray(inputRange As Range) As Variant()
Dim size As Integer
Dim inputValue As Variant, outputArray() As Variant
' inputValue will either be an variant array for ranges with more than 1 cell
' or a single variant value for range will only 1 cell
inputValue = inputRange
On Error Resume Next
size = UBound(inputValue)
If Err.Number = 0 Then
RangeToArray = inputValue
Else
On Error GoTo 0
ReDim outputArray(1 To 1, 1 to 1)
outputArray(1,1) = inputValue
RangeToArray = outputArray
End If
On Error GoTo 0
End Function