Funciones para manejo de matrices
El uso de las matrices (arrays) en Basic puede facilitarnos mucho las tareas de programación de macros. Usar una colección adecuada de funciones puede ahorrarnos muchas líneas de escritura y simplificar la lectura, análisis y depuración de nuestros programas.
A continuación mostramos algunas de estas funciones. No son todas las necesarias, ni pretenden ser perfectas. Como siempre ocurre cuando hablamos de programación, todo es mejorable.
Si consideras que tu función es más adecuada no dudes en mandarnos un correo con ella y la integraremos en este artículo.
Comentarios del código
En todas las funciones se ha agregado ByRef o ByVal definiendo el sistema de pasar el argumento según se ha considerado necesario para un adecuado funcionamiento.
Por defecto OOo Basic considera que los argumentos se pasan siempre por referencia; por lo tanto, y aunque es innecesario, se ha agregado ByRef para mejorar la lectura y comprensión de la función.
Las variables que se han utilizado en las funciones se han nombrado siguiendo el siguiente esquema:
- u para almacenar el ordinal del último elemento de la matriz devuelto por la función uBound.
- l para almacenar el ordinal del primer elemento de la matriz devuelto por la función lBound, dado que puede ser 0 (por defecto) o 1 según se haya establecido el parámetro Option Base.
- a para el array a().
Añadir un nuevo elemento a un array
La función aAdd nos permite agregar un nuevo elemento al final de una matriz.
Function aAdd( ByRef a(), ByVal xValor ) '-------------------------------------------------------------------------------------------- ' Agrega un elemento a un array y lo llena con xValor ' se puede llamar como función [ a = aadd( a, "5") ] o como subrutina [ aadd a, "5" ] Dim u As Long u = UBound( a ) + 1 ReDim Preserve a( u ) a(u) = xValor aAdd = a End Function
Dado que la matriz se pasa por referencia, podemos utilizarla como subrutina o como función:
' Como subrutina aAdd miArray, 1000 ' Como función miArray = aAdd( miArray, 1000 )
Eliminar un elemento o rango de elementos de un array
La función aDel nos permite eliminar un elemento o rango de elementos de una matriz. Los argumentos nIni y nFin tienen la siguiente operativa:
- nIni: Si es -1 indica que se pretende eliminar el último elemento de la matriz. Cualquier otro valor indica el elemento que se desea eliminar en la matriz. Si se utiliza junto con nFin indicará cual es el primer elemento del rango de elementos a eliminar en la matriz.
- nFin: Su uso es opcional. Indica el último elemento del rango de elementos a eliminar en la matriz.
Function aDel( ByRef a(), nIni As Long, Optional nFin As Long ) '-------------------------------------------------------------------------------------------- ' Elimina elementos de un array ' se puede llamar como función [ a = aDel( a, 5) ] o como subrutina [ aDel a, 5 ] ' si nIni es -1 se eliminará el último elemento Dim aTmp(), u As Long, r As Long, n As Long If IsMissing( nFin ) Then nFin = nIni On Local Error GoTo error_aDel u = UBound(a()) If nIni = -1 Then ' clave especial, borrar el último elemento ReDim aTmp(u-1) For n=0 To u-1 aTmp(n)=a(n) Next Else ReDim aTmp(u-(nFin-nIni)-1) For n=0 To nIni-1 aTmp(n)=a(n) Next r=n For n=nFin+1 To u aTmp(r)=a(n) r=r+1 Next End If a() = aTmp() aDel = a() Exit Function error_aDel: ' sólo tiene un elemento o no se ha inicializado el array ReDim a() aDel = a() End Function
Dado que la matriz se pasa por referencia, podemos utilizarla como subrutina o como función:
' Como subrutina aDel miArray, 3 'Como función: miArray = aDel( miArray, 3 )
Se ha utilizado el sistema de control de error para dos supuestos: se intenta eliminar el último elemento del array o éste no tiene elementos; en ambos casos devuelve un array vacío sin elementos.
No hemos utilizado Redim Preserve para reducir el tamaño de la matriz cuando se trata de eliminar el último elemento porque extrañamente no "preserva" el contenido.
Buscar un dato en un array unidimensional
La función aSeek nos permite encontrar la posición que ocupa un dato en una matriz. Opcionalmente se le puede indicar desde que elemento desea que se inicie la búsqueda.
Function aSeek( ByRef a(), xValor, Optional nIni ) As Long '-------------------------------------------------------------------------------------------- ' Busca en un array unidimensional. nIni indica desde qué posición se inicia la búsqueda Dim n As Long, l As Long, u As Long l = LBound( a ) u = UBound( a ) If Not IsMissing( nIni ) Then l = nIni For n=l To u If a(n) = xValor Then Exit For Next n If n > u Then n = -1 ' no se ha encontrado aSeek = n End Function
Buscar un dato en un array bidimensional
La función aSeekMD nos permite encontrar la posición que ocupa un dato en la dimensión x una matriz de y dimensiones. Opcionalmente se le puede indicar desde que elemento desea que se inicie la búsqueda.
Function aSeekMD( ByRef a(), nDimension As Long, xValor, Optional nIni ) As Long '-------------------------------------------------------------------------------------------- ' Busca en la dimensión nDimension de un array multidimensional. ' nIni indica desde qué posición se inicia la búsqueda Dim n As Long, l As Long, u As Long l = LBound( a, nDimension ) u = UBound( a, nDimension ) If Not IsMissing( nIni ) Then l = nIni For n=l To u If a(nDimension,n) = xValor Then Exit For Next n If n > u Then n = -1 ' no se ha encontrado aSeekMD = n End Function
Puedes probar con este ejemplo:
Dim a(3,2) For n=0 To 3 For m=0 To 2 j=j+1 a(n,m)=j Next Next MsgBox aSeekMD( a, 2, 9 ) ' devuelve 2
Recordemos que la notación de matrices multidimensionales es:
Buscar un dato en un array que contiene arrays
La función aSeekMArray nos permite encontrar la posición que ocupa un dato en una matriz que está embebida en un elemento de otro array. Opcionalmente se le puede indicar desde que elemento desea que se inicie la búsqueda.
Es parecido a utilizar arrays multidimensionales, pero la notación es diferente.
Function aSeekMArray( ByRef a(), nDimension As Long, xValor, Optional nIni ) As Long '-------------------------------------------------------------------------------------------- ' Busca en la dimensión nDimension de un array multidimensional. ' nIni indica desde qué posición se inicia la búsqueda Dim n As Long, l As Long, u As Long l = LBound( a(nDimension) ) u = UBound( a(nDimension) ) If Not IsMissing( nIni ) Then l = nIni For n=l To u If a(nDimension)(n) = xValor Then Exit For Next n If n > u Then n = -1 ' no se ha encontrado aSeekMArray = n End Function
Puedes probar con este ejemplo:
Dim a() a = Split("1,2,3;4,5,6;7,8,9;10,11,12", ";") For n=0 To 3 a(n) = Split(b(n),",") Next MsgBox aSeekMArray( a, 2, "8") ' devuelve 1
Indicar que buscar el valor de texto "8" en lugar del valor numérico 8 es debido a cómo hemos contruido las matrices de la prueba.
Recordemos que la notación de matrices contenidas en otras matrices es:
Eliminar los elementos vacíos de un array
La función aRemoveEmpty nos permite eliminar los elementos vacíos de una matriz.
Function aRemoveEmpty ( ByRef a() ) '-------------------------------------------------------------------------------------------- ' elimina los elementos vacíos de un array ' se puede llamar como función o como subrutina Dim n As Long, u As Long, l As Long u = UBound( a ) l = LBound( a ) For n = u To l Step -1 If Trim(a(n))= "" Then a = aDel( a, n ) Next aRemoveEmpty = a End Function
Dado que la matriz se pasa por referencia, podemos utilizarla como función o como subrutina:
' Como subrutina aRemoveEmpty miArray ' Como función miArray = aRemoveEmpty( miArray )
Eliminar elementos duplicados en un array
La función aRemoveDuplicates elimina los elementos repetidos en una matriz.
Function aRemoveDuplicates ( ByRef a() ) '-------------------------------------------------------------------------------------------- ' elimina los elementos duplicados de un array ' se puede llamar como función o como subrutina Dim n As Long, u As Long, l As Long u = UBound( a ) l = LBound( a ) Do While True For n = l+1 To u If a(n) = a(l) Then a = aDel( a, n ) u = u-1 l = l-1 EndIf Next l = l+1 If l > u Then Exit Do Loop aRemoveDuplicates = a End Function
Dado que la matriz se pasa por referencia, podemos utilizarla como función o como subrutina:
' Como subrutina aRemoveDuplicates miArray ' Como función miArray = aRemoveDuplicates( miArray )
Rellena todos los elementos de un array
La función aFill nos permite rellenar todos los elementos de una matriz con el dato pasado.
Function aFill( ByRef a(), ByVal xValor) '-------------------------------------------------------------------------------------------- ' llena el array con xValor por valor, no por referencia ' se puede llamar como función o como subrutina Dim n As Integer For n = LBound(a) To UBound(a) a(n) = xValor Next aFill = a End Function
Al pasar el dato por valor garantizamos la independencia de los elementos de la matriz de las variables o campos con los que se rellene.
Dado que la matriz se pasa por referencia, podemos utilizarla como función o como subrutina:
' Como subrutina aFill miArray, "Hola" ' Como función miArray = aFill( miArray, "Hola" )
Ordenar un array unidimensional
La subrutina aSort nos permite ordenar de forma ascendente una matriz unidimensional. Opcionalmente se le puede indicar un rango de elementos a ordenar, dejando en este caso el resto sin ordenar.
Sub aSort( ByRef a(), Optional nPri, Optional nUlt) '-------------------------------------------------------------------------------------------- ' ordena un array unidimensional en orden ascendente ' opcional ordenar parcialmente el array Dim nIndi As Integer, nUindi As Integer, n As Integer Dim x, nCentro If IsMissing(nPri) Then nPri = 0 If IsMissing(nUlt) Then nUlt = UBound(a) nIndi = nPri nUindi = nUlt n = Int((nIndi + 1 + nUindi) / 2) nCentro = a(n) Do Until nIndi > nUindi Do While a(nIndi) < nCentro nIndi = nIndi + 1 Loop Do While a(nUindi) > nCentro nUindi = nUindi - 1 Loop If nIndi <= nUindi Then x = a(nIndi) a(nIndi) = a(nUindi) a(nUindi) = x nIndi = nIndi + 1 nUindi = nUindi - 1 End If Loop If nPri < nUindi Then aSort a, nPri, nUindi End If If nUlt > nIndi Then aSort a, nIndi, nUlt End If End Sub
Ejemplo de uso
Dim a() a = Split( "3,2,1,0,9,8,7,6,5,4", ",") aSort a MsgBox Join(a, ",") ' resultado "0,1,2,3,4,5,6,7,8,9" a = Split( "3,2,1,0,9,8,7,6,5,4", ",") aSort a, 3 MsgBox Join(a, ",") ' resultado "3,2,1,0,4,5,6,7,8,9" a = Split( "3,2,1,0,9,8,7,6,5,4", ",") aSort a, 3, 7 MsgBox Join(a, ",") ' resultado "3,2,1,0,6,7,8,9,5,4"
Clonar un array
La función aClone nos permite crear un duplicado de un array.
Function aClone( a() ) '-------------------------------------------------------------------------------------------- ' crea un duplicado del array pasado Dim l As Long, u As Long, n As Long, x() l = LBound( a ) u = UBound( a ) ReDim x(u) For n=l To u: x(n) = a(n) : Next aClone = x() End Function
La copia creada es independiente del array original, como demuestra el siguiente código.
Dim a() As String, b() As Long a = Array(4,3,2,1) b = aClone(a) MsgBox Join(a, ",") & " / " & Join(b,",") ' obtenemos 4,3,2,1 / 4,3,2,1 asort a MsgBox Join(a, ",") & " / " & Join(b,",") ' obtenemos 1,2,3,4 / 4,3,2,1
Obtener el último elemento de un array
La función aTail devuelve el último elemento de una matriz.
Function aTail( a() ) '-------------------------------------------------------------------------------------------- ' devuelve el último elemento de un array aTail = a( UBound(a) ) End Function
Evaluar si un array está vacío
La función aIsEmpty devuelve VERDADERO si el array está vacío.
Function aIsEmpty( a() ) As Boolean '-------------------------------------------------------------------------------------------- ' devuelve true si el array está vacío On Local Error GoTo Error_aVacio aIsEmpty = UBound(a) Exit Function Error_aVacio: On Error GoTo 0 aIsEmpty = True End Function