Matrices
Es posible manipular muchos datos en una sola variable utilizando matrices. Pueden ser de mucha utilidad o convertirse en un verdadero galimatías si no se manejan correctamente.
Es importante que aprendas a utilizarlas, pues muchas estructuras de OpenOffice.org vienen implementadas en matrices.
Sintaxis básica de una matriz
La sintaxis más sencilla para declarar una matriz es la siguiente:
En donde Nombre_Matriz tiene que cumplir las mismas condiciones que para nombrar las macros y las variables vistas en Declarando y usando variables.
Tamaño se refiere al número de elementos que contendrá la matriz. Si como TipoVariable se indica Byte, podrá almacenar 255 elementos; si es Integer, 32.000, y si es Long, más de dos mil millones, lo que tal vez quiera decir que es hora de pasar a usar bases de datos.
En todo caso, el tamaño máximo está condicionado por el limite de la memoria Ram del equipo donde se ejecute.
Declarar matrices unidimensionales
Resulta fácil pensar en las matrices como una lista de valores en su presentación más sencilla, o en una tabla de filas y columnas en las mas compleja.
Por ejemplo, una lista de los días de la semana sería así:
- Domingo
- Lunes
- Martes
- Miércoles
- Jueves
- Viernes
- Sábado
Almacenar la lista en una matriz sería así:
Sub Ejemplo_Matrices1()
Dim miSemana(6) As String
miSemana(0) = "Domingo"
miSemana(1) = "Lunes"
miSemana(2) = "Martes"
miSemana(3) = "Miércoles"
miSemana(4) = "Jueves"
miSemana(5) = "Viernes"
miSemana(6) = "Sábado"
MsgBox miSemana( 3 )
End Sub
Con un simple bucle se puede acceder a toda la matriz:
Sub Ejemplo_Matrices2()
Dim miSemana(6) As String
Dim co1 As Integer
miSemana(0) = "Domingo"
miSemana(1) = "Lunes"
miSemana(2) = "Martes"
miSemana(3) = "Miércoles"
miSemana(4) = "Jueves"
miSemana(5) = "Viernes"
miSemana(6) = "Sábado"
For co1 = 0 To 6
MsgBox miSemana( co1 ), 64, "Toda la semana"
Next
End Sub
Option Base
El primer elemento de la matriz es el elemento 0 (cero), que es la forma predeterminada. Podemos forzar a que el primer elemento sea el 1 (uno), usando la palabra clave Option Base de la siguiente forma:
Option Explicit
Option Base 1
Sub Ejemplo_Matrices3()
Dim miSemana(7) As String
Dim co1 As Integer
miSemana(1) = "Domingo"
miSemana(2) = "Lunes"
miSemana(3) = "Martes"
miSemana(4) = "Miércoles"
miSemana(5) = "Jueves"
miSemana(6) = "Viernes"
miSemana(7) = "Sábado"
For co1 = 1 To 7
MsgBox miSemana( co1 ), 64, "Toda la semana"
Next
End Sub
Option Base debe declararse al principio del módulo. La mayoría de las estructuras de OpenOffice.org inician en 0 (cero), así que será preferible utilizar este valor de inicio como predeterminado.
Si te es necesario declarar una matriz con un inicio o un fin diferente puedes usar la siguiente variante para la declaración de matrices.
En donde Inicio y Fin pueden ser incluso valores negativos como en los ejemplos siguientes (Fin debe ser un valor mayor que Inicio).
Sub Ejemplo_Matrices4()
Dim misNumeros(5 To 14) As Integer
Dim misColores(-5 To 4) As String
misNumeros(5) = 123
misNumeros(6) = 345
misNumeros(7) = 567
misNumeros(8) = 890
misNumeros(9) = 135
misNumeros(10) = 246
misNumeros(11) = 147
misNumeros(12) = 258
misNumeros(13) = 369
misNumeros(14) = 951
misColores(-5) = "Azul"
misColores(-4) = "Verde"
misColores(-3) = "Morado"
misColores(-2) = "Rojo"
misColores(-1) = "Blanco"
misColores(0) = "Rosa"
misColores(1) = "Violeta"
misColores(2) = "Gris"
misColores(3) = "Negro"
misColores(4) = "Oro"
MsgBox misNumeros( 9 ), 64, "Números"
MsgBox misColores( 0 ), 64, "Colores"
End Sub
En los dos casos las matrices tienen los mismos diez elementos; una almacena números y la otra, texto, pero muy bien podemos combinar datos si declaramos la matriz de tipo Variant, como en el siguiente ejemplo:
Sub Ejemplo_Matrices5
Dim misDatos(5) As Variant
Dim co1 As Integer
misDatos( 0 ) = "Mauricio Baeza"
misDatos( 1 ) = 1974
misDatos( 2 ) = "Miguel Angel 64"
misDatos( 3 ) = "Mexico"
misDatos( 4 ) = "D.F."
misDatos( 5 ) = 37000
For co1 = 0 To 5
MsgBox misDatos( co1 ), 64, "Mis datos"
Next
End Sub
LBound y UBound
Cuando queremos recorrer una matriz con un bucle es muy probable no conocer los valores de Inicio y Fin de una matriz.
OOo Basic cuenta con dos funciones para conocer estos valores:
Sub Ejemplo_Matrices6
Dim misDatos() As Integer
Dim co1 As Integer
misDatos() = Array( 87,58,26,35,98,51,26,58,12,48,35,16 )
MsgBox "Limite Inferior = " & Str( LBound( misdatos() ))
MsgBox "Limite Superior = " & Str( UBound( misdatos() ))
For co1 = LBound( misdatos() ) To UBound( misDatos() )
MsgBox misDatos( co1 ), 64, "Mis datos"
Next
End Sub
En el ejemplo aprendemos cuatro nuevas funciones de OOo Basic
- Array nos permite crear una matriz introduciendo directamente los valores que contendrá, separados por una coma.
- LBound nos devuelve el limite inferior de una matriz.
- UBound nos devuelve el limite superior.
- Str convierte en cadena de texto (String) el argumento pasado.
Se puede declarar una matriz de un determinado tamaño y utilizar Array para llenar la matriz sin que necesariamente correspondan el número de elementos, como muestran los siguientes ejemplos:
Sub Ejemplo_Matrices7
Dim misDatos1(5) As Variant
Dim misDatos2(5) As Variant
Dim misDatos3(3) As Variant
Dim co1 As Integer
'Llenamos la primer matriz con el numero exacto de elementos declarados
misDatos1() = Array( "Lizet", 30, "Hola", 45, "Prueba", 15 )
MsgBox "Limite Inferior = " & Str( LBound( misdatos1() )) & Chr( 13 ) & _
"Limite Superior = " & Str( UBound( misdatos1() ))
'Con menos elementos
misDatos2() = Array( "Paola", 25, "Hola" )
MsgBox "Limite Inferior = " & Str( LBound( misdatos2() )) & Chr( 13 ) & _
"Limite Superior = " & Str( UBound( misdatos2() ))
'Con mas elementos
misDatos3() = Array( "Mariana", 27, "Hola", 18, "Prueba" )
MsgBox "Limite Inferior = " & Str( LBound( misdatos3() )) & Chr( 13 ) & _
"Limite Superior = " & Str( UBound( misdatos3() ))
End Sub
Al observar los valores inferior y superior que nos devuelve cada matriz, vemos que la matriz se redimensiona con el número de elementos que define la función Array, sin importar cómo hayamos declarado la matriz.
Redimensionar matrices con Redim y Redim Preserve
Cambiar el número de elementos que puede contener una matriz de forma dinámica durante la ejecución de una macro es una tarea habitual de programación, por ello existen varias alternativas para lograr este propósito. OOo Basic cuenta con una instrucción especifica para cambiar las dimensiones de una matriz: ReDim, y se utiliza de la siguiente forma:
Sub Ejemplo_Matrices8
Dim misAmigos(2) As String
Dim co1 As Integer
misAmigos(0) = "Edgar" : misAmigos(1) = "Gloria" : misAmigos(2) = "Toñito"
For co1 = LBound( misAmigos() ) To UBound( misAmigos() )
MsgBox Str( co1 ) & " - " & misAmigos( co1 ), 64, "Mis amigos"
Next
Redim misAmigos(4)
misAmigos(3) = "Lidia": misAmigos(4) = "Anita"
For co1 = LBound( misAmigos() ) To UBound( misAmigos() )
MsgBox Str( co1 ) & " - " & misAmigos( co1 ), 64, "Mis amigos"
Next
End Sub
En el código el segundo bucle sólo muestra los valores de los índices 3 y 4. Es debido a que al redimensionar la matriz con ReDim se elimina el contenido previo de la matriz. Si deseamos mantener los valores previos deberemos utilizar Redim Preserve:
Sub Ejemplo_Matrices9
Dim misAmigos(2) As String
Dim co1 As Integer
misAmigos(0) = "Edgar": misAmigos(1) = "Gloria" : misAmigos(2) = "Toñito"
For co1 = LBound( misAmigos() ) To UBound( misAmigos() )
MsgBox Str( co1 ) & " - " & misAmigos( co1 ), 64, "Mis amigos"
Next
ReDim Preserve misAmigos(4)
misAmigos(3) = "Lidia": misAmigos(4) = "Anita"
For co1 = LBound( misAmigos() ) To UBound( misAmigos() )
MsgBox Str( co1 ) & " - " & misAmigos( co1 ), 64, "Mis amigos"
Next
End Sub
ReDim no sólo sirve para aumentar elementos; también sirve para disminuirlos. Pero tiene el inconveniente de que ni aun usando Preserve mantiene los valores previos, como lo demuestra el siguiente ejemplo:
Sub Ejemplo_Matrices10
Dim misNumeros(9) As Integer
Dim co1 As Integer
misNumeros() = Array( 1,2,3,4,5,6,7,8,9,10 )
For co1 = LBound( misNumeros() ) To UBound( misNumeros() )
MsgBox misNumeros( co1 ), 64, "Mis números"
Next
ReDim Preserve misNumeros(4)
For co1 = LBound( misNumeros() ) To UBound( misNumeros() )
MsgBox misNumeros( co1 ), 64, "Mis números"
Next
End Sub
Una primera solución es la propuesta siguiente:
Sub Ejemplo_Matrices11
Dim misNumeros(9) As Integer
Dim mTmp() As String
Dim co1 As Integer
'Llenamos la matriz con 10 números
misNumeros() = Array( 1,2,3,4,5,6,7,8,9,10 )
'Redimensionamos la matriz temporal
Redim mTmp(4)
'Pasamos los valores a la matriz temporal
For co1 = LBound( mTmp() ) To UBound( mTmp() )
mTmp( co1 ) = misNumeros( co1 )
Next
'Redimensionamos la matriz original
Redim misNumeros(4)
'Copiamos loa valores temporales
misNumeros() = mTmp()
'Verificamos que estén los datos
For co1 = LBound( misNumeros() ) To UBound( misNumeros() )
MsgBox misNumeros( co1 ), 64, "Mis números"
Next
'Borramos la memoria usada por la matriz temporal
Erase mTmp
End Sub
Como es una tarea habitual (el disminuir de tamaño una matriz y desear mantener los valores restantes), es una tarea idónea para convertirla en una subrutina o si lo deseas, en una función como se verá en el tema Funciones y Subrutinas.
Si optamos por una subrutina, podemos pasar como argumentos la matriz a redimensionar y el nuevo tamaño: si es mayor solo redimensiona, si es menor, copia los valores a mantener y redimensiona, si es igual la deja tal cual.
Sub RedimencionarMatriz( Matriz() As Variant, ByVal Tamano As Integer)
Dim mTmp() As Variant
Dim co1 As Integer
If Tamano > UBound( Matriz() ) Then
ReDim Preserve Matriz( Tamano )
ElseIf Tamano < UBound( Matriz() ) Then
ReDim mTmp( Tamano )
For co1 = LBound( mTmp() ) To UBound( mTmp() )
mTmp( co1 ) = Matriz( co1 )
Next
Redim Matriz( Tamano )
Matriz() = mTmp()
Erase mTmp
End If
End Sub
Si optamos por una función, puede hacer exactamente lo mismo, pero devolviendo la matriz en lugar de manipular la matriz pasada como argumento.
Function FuncionRedimencionarMatriz( Matriz() As Variant, ByVal Tamano As Integer) As Variant
Dim mTmp() As Variant
Dim co1 As Integer
If Tamano > UBound( Matriz() ) Then
ReDim Preserve Matriz( Tamano )
ElseIf Tamano < UBound( Matriz() ) Then
ReDim mTmp( Tamano )
For co1 = LBound( mTmp() ) To UBound( mTmp() )
mTmp( co1 ) = Matriz( co1 )
Next
Redim Matriz( Tamano )
Matriz() = mTmp()
Erase mTmp
End If
FuncionRedimencionarMatriz = Matriz()
End Function
Para que no quede duda, veamos su uso tanto como subrutina como función:
'Usándola como subrutina
Sub Ejemplo_Matrices12
Dim misNumeros(9) As Variant
Dim mTmp() As String
Dim co1 As Integer
misNumeros() = Array( 1,2,3,4,5,6,7,8,9,10 )
Call RedimencionarMatriz( misNumeros(), 15)
misNumeros(12) = 12
MsgBox misNumeros(12)
Call RedimencionarMatriz( misNumeros(), 5)
'Verificamos que estén los datos
For co1 = LBound( misNumeros() ) To UBound( misNumeros() )
MsgBox misNumeros( co1 ), 64, "Mis números"
Next
End Sub
'Usándola como función
Sub Ejemplo_Matrices13
Dim misNumeros(9) As Variant
Dim mTmp() As String
Dim co1 As Integer
'Llenamos la matriz
misNumeros() = Array( 1,2,3,4,5,6,7,8,9,10 )
'Llamamos a la función, observa el paso de argumentos, crecemos la matriz
misNumeros() = FuncionRedimencionarMatriz( misNumeros(), 15 )
'Asignamos un valor al indice 12
misNumeros(12) = 12
'Verificamos que lo haya guardado
MsgBox misNumeros(12)
'Llamamos de nuevo a la función, esta vez la disminuimos
misNumeros() = FuncionRedimencionarMatriz( misNumeros(), 5 )
'Verificamos que estén los datos
For co1 = LBound( misNumeros() ) To UBound( misNumeros() )
MsgBox misNumeros( co1 ), 64, "Mis números"
Next
End Sub
Copiar matrices
OOo Basic permite fácilmente copiar una matriz en otra:
Al copiar matrices de este modo quedan vinculadas como se demuestra con el siguiente ejemplo:
Sub CopiarMatrices()
Dim mDatos1()
Dim mDatos2()
mDatos1 = Array(0,1,2,3,4,5)
'Copio las matrices
mDatos2 = mDatos1
'Muestro el segundo valor de la segunda matriz
MsgBox mDatos2(1)
'Modifico este valor
mDatos2(1)= "B"
'Muestro el segundo valor de la primer matriz
MsgBox mDatos1(1)
'Vuelvo a modificar este valor en esta matriz
mDatos1(1)= "C"
'Muestro el valor en la otra matriz
MsgBox mDatos2(1)
End Sub
Es debido a que la anterior asignación en realidad no crea una matriz independiente, sino una variable que apunta a la anterior matriz.
Erase
La palabra clave Erase permite borrar de memoria las matrices dinámicas que ya no usemos.
Aunque ahora la mayoría de las computadoras disponen de muchos megas de RAM, es conveniente mantener el control de la cantidad de memoria que usas en tus macros.
Matrices multidimensionales
Hemos visto la declaración y el uso de matrices de una sola dimensión, pero es posible declarar y utilizar matrices de más de una dimensión.
La sintaxis para declarar matrices multidimensionales es la siguiente:
Observa como ahora, le indicamos dos dimensiones separadas por una coma; un ejemplo es más ilustrativo:
Sub Matrices_Multidimension1
Dim mDatos( 2, 2 ) As String
'Llenamos los datos
mDatos( 0, 0 ) = "0-0"
mDatos( 0, 1 ) = "0-1"
mDatos( 0, 2 ) = "0-2"
mDatos( 1, 0 ) = "1-0"
mDatos( 1, 1 ) = "1-1"
mDatos( 1, 2 ) = "1-2"
mDatos( 2, 0 ) = "2-0"
mDatos( 2, 1 ) = "2-1"
mDatos( 2, 2 ) = "2-2"
'Mostramos algunos datos
MsgBox mDatos( 0, 0 )
MsgBox mDatos( 1, 1 )
MsgBox mDatos( 2, 2 )
End Sub
Piensa en las matrices de dos dimensiones como en una hoja de calculo formada por filas y columnas; la matriz anterior quedaría así.
0 | 1 | 2 | |
---|---|---|---|
0 | 0-0 | 1-0 | 2-0 |
1 | 0-1 | 1-1 | 2-1 |
2 | 0-2 | 1-2 | 2-2 |
Por supuesto puedes declarar y utilizar matrices de más de dos dimensiones. ¿Hasta cuantas? El limite viene determinado una vez más por la cantidad de memoria RAM de que disponga la computadora donde se ejecute la macro. Matrices con más de tres dimensiones no son complicadas de manipular, pero suele ser difícil imaginar más de tres dimensiones.
Otro ejemplo: creamos una matriz de 10x10 elementos y la llenamos con valores aleatorios entre 1 y 100:
Sub Matrices_Multidimension2
Dim mNumeros( 9, 9 ) As Integer
Dim co1 As Integer, co2 As Integer
'Recuerda que por default los índices de las matrices empieza en cero
For co1 = 0 To 9
For co2 = 0 To 9
mNumeros( co1, co2 ) = Rnd() * 100 + 1
Next
Next
'Comprobamos un índice cualquiera
MsgBox mNumeros( 4, 4 )
End Sub
La función Rnd() nos devuelve un número aleatorio entre 0 y 1, que al ser multiplicado por un valor (el valor superior del rango deseado) y sumarle otro valor (el valor inferior del rango deseado) obtenemos en cada paso un número aleatorio entre estos dos valores. Tenemos pues un algoritmo para obtener números aleatorios entre dos valores dados.
Con las matrices de dos dimensiones se puede simular una tabla de una base de datos o una hoja de calculo, donde podemos almacenar una serie de datos organizados en columnas (que podemos denominar campos) y en filas (que podemos denominar registros); veamos un sencillo ejemplo:
Sub Matrices_Multidimension3
Dim mTelefonos( 2, 1 ) As String
mTelefonos( 0, 0 ) = "Gloria"
mTelefonos( 0, 1 ) = "12345678"
mTelefonos( 1, 0 ) = "Antonio"
mTelefonos( 1, 1 ) = "87654321"
mTelefonos( 2, 0 ) = "Lidia"
mTelefonos( 2, 1 ) = "32458924"
MsgBox "El teléfono de " & mTelefonos( 2, 0 ) & " es " & mTelefonos( 2, 1 )
End Sub
Lo interesante es darle la oportunidad al usuario de ir introduciendo estos datos y que la matriz crezca según las necesidades de este. Veamos como:
Sub Matrices_Multidimension4
Dim mDirectorio( 0, 1 ) As String
Dim Nombre As String
Dim Telefono As String
Dim iContinuar As Integer
Dim co1 As Integer
Dim sTmp As String
Do
'Solicitamos el nombre, observa el uso de la función Trim para quitar espacios sobrantes
Nombre = Trim( InputBox( "Escribe un nombre", "Nombre" ) )
Telefono = Trim( InputBox( "Ahora su teléfono", "Teléfono" ) )
'Redimensionamos la matriz, pero OJO, solo la primer dimensión
Redim Preserve mDirectorio( co1, 1 )
'Guardamos los datos en el nuevo indice
mDirectorio( co1, 0 ) = Nombre
mDirectorio( co1, 1 ) =
'Vamos construyendo nuestro directorio
sTmp = sTmp & "El teléfono de " & mDirectorio( co1, 0 ) & " es " & mDirectorio( co1, 1 ) & Chr(13)
'Incrementamos nuestro contador de registros
co1 = co1 + 1
'Preguntamos si desea continuar
iContinuar = MsgBox( "¿Deseas capturar mas datos?", 4 + 32, "Continuar" )
Loop While iContinuar = 6
'Mostramos nuestro directorio
MsgBox sTmp
End Sub
Hemos utilizado el recurso de ir guardando los valores introducidos por el usuario en una variable temporal (sTmp), con lo cual, no estamos muy seguros de que efectivamente los datos estén siendo guardados dentro de la matriz.
Modifica la macro para que:
|
Matrices escalares
Las matrices permiten anidar otras matrices, es decir, que uno o más elementos de la matriz sean otra matriz, lo que algunos autores llaman matrices escalares. Veamos su uso:
Sub Matrices_Matrices1
Dim mDatos(2) As Variant
Dim mTmp As Variant
mDatos(0) = Array("Perro","Gato","Oso","Tiburón","Burro")
mDatos(1) = Array("Cedro","Pino","Caoba","Fresno")
mDatos(2) = Array("Cobre","Plata","Manganeso","Azufre","Potasio","Fierro")
mTmp = mDatos(0)
MsgBox mTmp(0)
mTmp = mDatos(1)
MsgBox mTmp(1)
mTmp = mDatos(2)
MsgBox mTmp(2)
End Sub
Se ha hecho uso de una variable temporal (mTmp) para asignar la matriz interna y así poder acceder a sus valores.
Algunas funciones y estructuras de OpenOffice.org que veremos más adelante están implementadas de estar forma, como una matriz dentro de otra, de ahí su importancia.
En realidad, su uso es muy sencillo; veamos un ejemplo:
Sub Matrices_Matrices2
Dim mDatos(3) As Variant
Dim mTmp As Variant
Dim co1 As Integer
Dim sCaracter As String
Dim sContra As String
'Llenamos los datos, observa como tenemos cuatro grupos, letras minúsculas, letras mayúsculas, números y caracteres especiales
mDatos(0) = Array( "a", "b" ,"c" ,"d" ,"e" ,"f" ,"g" ,"h" ,"i" ,"j" ,"k" ,"l" ,"m","n","ñ","o","p","k","r","s","t","u","v","w","x","y","z")
mDatos(1) = Array( "A" ,"B" ,"C" ,"D" ,"E" ,"F" ,"G" ,"H" ,"I" ,"J" ,"K" ,"L" ,"M","N","Ñ","O","P","Q","R","S","T","U","V","W","X","Y","Z")
mDatos(2) = Array("1","2","3","4","5","6","7","8","9","0")
mDatos(3) = Array( "\" ,"|" ,"!" ,"·" ,"$" ,"%" ,"&" ,"/" ,"(" ,")" ,"=" ,"?" ,"¿","¡","+","-","_",".",":",",",";","<",">","}","{","]","[")
'Nuestra contraseña sera de 10 caracteres
For co1 = 1 To 10
'Seleccionamos '''aleatoriamente''', UNO de los cuatro grupos
mTmp = mDatos( CInt( Rnd() * 3 ) )
'Seleccionamos '''aleatoriamente''', UN elemento del grupo, observa como usamos la función Rnd y la multiplicamos por el índice superior del grupo seleccionado
sCaracter = mTmp( CInt( Rnd() * UBound(mTmp) ) )
'Vamos juntando los caracteres de la contraseña
sContra = sContra & sCaracter
Next
'Mostramos la contraseña
MsgBox "Tu contraseña es: " & sContra
End Sub
Analizando el código vemos que no es tan complejo como parece.
Modifica la macro de modo que pregunte al usuario cuantos caracteres requiere para su contraseña; define un rango mínimo y máximo dentro del que pueda escoger, por ejemplo, entre 5 y 50 caracteres |
La forma de acceder directamente a los elementos de una matriz de matrices es utilizando un doble índice como nos muestra el siguiente ejemplo:
Sub Matrices_Matrices3()
Dim mDatos(1)
Dim co1 As Integer, co2 As Integer
mDatos(0) = Array(1,2,3,4,5,6,7,8,9,0)
mDatos(1) = Array(11,12,13,14,15,16,17,18,19,10)
For co1 = 0 To 1
For co2 = 0 To 9
MsgBox mDatos (co1) (co2)
Next
Next
End Sub
Importante
Valida siempre las dimensiones de una matriz (utilizando UBound y LBound) cuando accedes a sus elementos por medio de índices. Si el índice no existe se producirá un error en tiempo de ejecución |
Si tienes dudas acerca de lo aquí explicado, tienes algún problema con AOO, o quieres ampliar la información, no dudes en dirigirte al Foro Oficial en español de Apache OpenOffice para Macros y API UNO |