TL;DR — Un array 2D de VBA es un array con dos subíndices —una cuadrícula de filas y columnas,
g(row, column)—, no un array de arrays.Dim g(1 To 3, 1 To 4)es tres filas por cuatro columnas. El dato más útil con diferencia para trabajar en Excel: leerRange("A1:D3").Valuete entrega un array Variant bidimensional indexado desde 1 en un solo paso, y escribir un array de vuelta conRange(...).Value = arrlo escribe en un solo paso —por eso el procesamiento con arrays es drásticamente más rápido que iterar celda a celda—.
Sub SheetToArrayAndBack()
Dim data As Variant
data = Range("A1:D100").Value ' un solo acceso a la hoja -> array 2D indexado desde 1
Dim r As Long
For r = 1 To UBound(data, 1) ' filas
data(r, 4) = data(r, 2) * data(r, 3) ' col D = col B * col C, en memoria
Next r
Range("A1:D100").Value = data ' un solo acceso de vuelta -> instantaneo
End Sub
Un array 2D es donde se encuentran los arrays y las hojas de cálculo: una hoja es una cuadrícula, y la
forma más rápida de trabajar con un bloque de celdas es meterlo en un array 2D, calcular en memoria y
escribirlo de vuelta. Se apoya directamente en dimensionar arrays con ReDim y
leer su forma con UBound —una cuadrícula simplemente tiene un límite por
dimensión—. Lo único que hace tropezar a la gente es que los arrays de Range.Value están indexados
desde 1, y que ReDim Preserve no puede añadir filas.
Lo que aprenderás
- El modelo mental — una cuadrícula con dos subíndices,
g(row, column), no arrays anidados - Declarar y direccionar un array 2D con
Dim g(1 To 3, 1 To 4)yg(r, c) - El gordo:
Range.Valuete da un arrayVariant2D indexado desde 1 en un solo paso - Escribir un array de vuelta a un rango de una sola vez —y por qué eso es mucho más rápido—
- Dos casos límite: una sola celda no es un array, y una sola columna es
(n, 1) - Añadir filas: por qué
ReDim Preserveno puede, y qué hacer en su lugar - En qué se diferencia un «array de arrays» escalonado de un verdadero array 2D
El modelo mental: un array, dos subíndices
Un array unidimensional es una fila numerada de cajas: a(i). Un array bidimensional es una
cuadrícula —direccionas cada caja con dos números, una fila y una columna: g(r, c)—. Y lo
fundamental: es un único array que resulta estar direccionado de dos formas, no una lista cuyos
elementos son a su vez listas:
Dim g(1 To 3, 1 To 4) As Long ' 3 filas, 4 columnas = 12 elementos
g(1, 1) = 10 ' fila 1, columna 1
g(3, 4) = 99 ' fila 3, columna 4
El primer subíndice es por convención la fila, el segundo la columna —el mismo orden en que lees una referencia de celda—. Mantén ese orden coherente y un array 2D se corresponde limpiamente con un bloque rectangular de celdas.
Declarar y recorrer una cuadrícula
Declara los dos límites, luego itera con un For anidado —el externo sobre las filas, el interno sobre
las columnas— usando UBound con un número de dimensión:
Dim g(1 To 3, 1 To 4) As Long
Dim r As Long, c As Long
For r = LBound(g, 1) To UBound(g, 1) ' filas
For c = LBound(g, 2) To UBound(g, 2) ' columnas
g(r, c) = r * 10 + c
Next c
Next r
UBound(g, 1) es el recuento de filas, UBound(g, 2) el de columnas. Iterar de LBound a UBound en
cada dimensión significa que el mismo código funciona tanto si el array es 1 To n (como te lo da
Range.Value) como si está indexado desde cero.
El gordo: Range.Value es un array 2D indexado desde 1
Este es el dato que hace que valga la pena aprender los arrays 2D. Leer el .Value de un rango de varias
celdas te da, en un solo paso, un array Variant bidimensional cuyos límites empiezan en 1
—independientemente de dónde esté el rango en la hoja—:
Dim data As Variant
data = Range("C5:E7").Value ' un bloque de 3 filas y 3 columnas en cualquier parte de la hoja
' data es ahora data(1 To 3, 1 To 3) - SIEMPRE indexado desde 1, fila y luego columna
Debug.Print data(1, 1) ' el valor de C5
Debug.Print data(3, 3) ' el valor de E7
Fíjate en dos cosas. Primero, el array está indexado desde 1, no desde 0 —así que data(1, 1) es la
celda superior izquierda, y un bucle For i = 0 se saltaría la primera fila y se toparía con el error 9—.
Segundo, los índices son relativos al bloque, no a la hoja: data(1, 1) es la celda superior
izquierda del rango tanto si el rango es A1 como C5. Declara la variable receptora como Variant (no
As Long() etc.) —VBA te rellena un Variant 2D nuevo—.
Escríbelo de vuelta de una sola vez
El mismo truco funciona a la inversa. Asigna un array 2D con la forma correcta al .Value de un rango y
Excel escribe el bloque entero de golpe:
Range("C5:E7").Value = data ' escribe las 9 celdas en una sola operacion
Por eso el enfoque con arrays es rápido. Tocar las celdas de una en una cruza la frontera entre VBA y
Excel en cada lectura y escritura —miles de idas y vueltas para un rango grande—. Leer en un array,
calcular en memoria y escribir de vuelta significa solo dos cruces en total. Para cualquier cosa que
pase de unos cientos de celdas, esta es la diferencia entre una macro que se siente instantánea y otra que
ves avanzar a duras penas. El rango escrito debe coincidir con la forma del array (filas × columnas), así
que dimensiona el rango de destino a UBound(arr, 1) filas por UBound(arr, 2) columnas.
Dos casos límite que muerden
Una sola celda no es un array. Range("A1").Value devuelve un escalar corriente, no un array
1 To 1, 1 To 1 —así que el código que da por hecho un array fallará en un rango de una sola celda—. Si
el rango pudiera ser una sola celda, compruébalo con IsArray() antes de indexarlo.
Una sola fila o columna sigue siendo 2D. Range("A1:A10").Value es data(1 To 10, 1 To 1) —diez
filas, una columna— así que sigues direccionándolo como data(i, 1), no data(i). Lo mismo vale para una
sola fila: data(1, j). Es fácil olvidar el segundo subíndice en una porción «unidimensional» de una
hoja.
Añadir filas: ReDim Preserve no puede
Como ReDim Preserve solo redimensiona la última dimensión, no puedes ampliar
el recuento de filas (la primera dimensión) de un array 2D conservando los datos. Tres opciones prácticas:
- Dimensiona una vez. Si conoces el recuento de filas de antemano (una última fila, un recuento de
registros), haz
ReDimde la cuadrícula a su tamaño final antes del bucle y nunca usesPreserve. - Amplía las columnas en su lugar. Declara el array como columnas × filas para que la dimensión que
extiendes sea la última, luego transpón a la salida con
Application.Transpose. - Reconstruye. Para un crecimiento de verdad desconocido, recopila en una
Collectiono una estructura escalonada y construye el array 2D una sola vez al final.
Para el trabajo con hojas casi siempre aplica la primera opción, porque el recuento de filas es algo barato de averiguar antes de empezar.
Los arrays escalonados son otra cosa
Un verdadero array 2D es rectangular —cada fila tiene el mismo número de columnas—. Un array escalonado es un array unidimensional cuyos elementos son a su vez arrays, así que cada «fila» puede tener una longitud distinta. Lo direccionas con dos pares de corchetes, no con dos subíndices:
Dim jagged(1 To 2) As Variant
jagged(1) = Array(1, 2, 3) ' una fila de 3 elementos
jagged(2) = Array(9, 8) ' una fila de 2 elementos
Debug.Print jagged(1)(3) ' 3 <- dos pares de corchetes, no (1, 3)
Los arrays escalonados son útiles para datos irregulares, pero no interoperan con Range.Value, que
siempre es rectangular. Cuando los datos son un rectángulo —que es lo que siempre es un bloque de hoja—
recurre a un verdadero array 2D.
Cómo te ayuda ExcelMaster
Trabajar con un bloque de celdas de forma eficiente es un solo patrón —leer Range.Value en un array 2D
indexado desde 1, calcular en memoria, escribirlo de vuelta de una sola vez— y las trampas están todas en
los detalles: el índice desde 1, el escalar de una sola celda, la fila que no puedes ampliar con
Preserve.
ExcelMaster te deja describir la
tarea —«para cada fila del rango usado, pon cantidad por precio en la columna E»— y lee el bloque en un
array 2D, itera de 1 a UBound(arr, 1), escribe el resultado de vuelta en una sola asignación, y
gestiona los casos de una sola celda y una sola columna, así que la macro es a la vez correcta y rápida.
Tú conservas el libro y el código.
Preguntas frecuentes
¿Cómo declaro un array 2D en VBA?
Da dos límites separados por una coma: Dim g(1 To 3, 1 To 4) As Long crea una cuadrícula de tres filas y
cuatro columnas. Direcciona un elemento con dos subíndices, g(row, column), por ejemplo g(2, 3). Para
un array 2D dinámico, decláralo abierto con Dim g() y dimensiónalo más tarde con ReDim g(1 To 3, 1 To 4).
¿Cómo leo un rango en un array 2D en VBA?
Asigna el .Value del rango a un Variant: Dim data As Variant: data = Range("A1:D100").Value. VBA
rellena un array bidimensional indexado desde 1, data(1 To rows, 1 To columns), en un solo paso.
Direcciona las celdas como data(row, column), donde los índices son relativos a la esquina superior
izquierda del rango. Esta es la forma más rápida de procesar muchas celdas.
¿Por qué mi array de Range.Value está indexado desde 1 en lugar de desde 0?
Porque así es como lo devuelve Excel —un array de Range.Value siempre empieza en el índice 1 en ambas
dimensiones, sin importar dónde esté el rango en la hoja—. Itera de LBound(data, 1) a UBound(data, 1)
(o simplemente 1 To UBound) para no saltarte la primera fila ni salirte del final con un bucle indexado
desde 0.
¿Cómo escribo un array 2D de vuelta a un rango?
Asígnalo al .Value del rango: Range("A1:D100").Value = data. El rango debe tener la misma forma que el
array —el mismo número de filas y columnas— así que dimensiona el destino con UBound(data, 1) filas y
UBound(data, 2) columnas. Esto escribe el bloque entero en una sola operación, mucho más rápido que
celda a celda.
¿Puedo añadir una fila a un array 2D en VBA?
No con ReDim Preserve —solo puede redimensionar la última dimensión (la de columnas), así que ampliar el
recuento de filas lanza el error 9—. O bien dimensionas el array a su recuento final de filas antes del
bucle, lo declaras como columnas × filas y transpones, o lo construyes a partir de una Collection y
creas el array 2D una sola vez al final.
Probado en
Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 24/09/2026.
Guías relacionadas: VBA ReDim · VBA UBound · VBA Array · VBA For Loop · VBA Range
