viernes, 4 de octubre de 2024

Funciones. Matrices

Borrar posiciones de una matriz.

En [esta entrada] hablamos del intercambio de datos entre matrices desiguales (de tamaño diferente) y mostré en ella una función (mejor dicho, dos funciones) que permitían reducir el tamaño de una matriz atendiendo a un criterio dado, concretamente a la ausencia de contenido ("") en determinadas posiciones. Quedaba pendiente la explicación de ambas, así que empecemos por la primera (1).



La formulación original de la función es la siguiente (2):

Function aRemoveEmpty ( ByRef a() )

   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) 'Llama a la función aDel() si se da la condición ""
   Next

   aRemoveEmpty = a

End Function

Lo primero que observamos es que en la declaración del parámetro de la función empleamos la expresión ByRef para especificar el modo en que se trabaja con la función. Sobre esta cuestión ver aclaración [en  esta entrada] (3). Mediante el parámetro a() desde la función accedemos  a la matriz que vamos a pasar desde el script (en este caso, [como sabemos], la matriz mRecurso() en mRecurso()=  aRemoveEmpty (mRecurso())).

En segundo lugar se han declarado tres variables (Dim n As Long, u As Long, l As Long), todas ellas de tipo Long, aunque si las tratamos como Integer podría ser suficiente (4), dos de ellas (l y u, respectivamente) para asignar el valor posición inicial (LBound()) y final (UBound()) de la matriz-parámetro (como veremos a continuación) y la tercera (n) como contador del bucle que vamos a crear.

Salvo esta tercera (el contador), las otras dos podrían ser obviadas si usamos las referencias directas a ambas posiciones en el bucle. Veremos la alternativa más abajo. No obstante, de este modo se simplifica la formulación de los límites del bucle, quedando éste simplificado y más claramente formulado.

Tras a asignación de contenido a las variables l y u, se formula un bucle que tiene dos particularidades, derivando la segunda de la primera:
  • Que se organiza en sentido fin-inicio (en lugar del orden normal), esto es desde UBound(a()) hasta LBound(a()) (5)
  • Y, en consecuencia, el recorrido se hace también en orden inverso mediante Step -1)
Esto supone que el bucle (For n = u To l Step -1) recorre la matriz-parámetro desde su posición final (u - > u = UBound(a)) hasta su posición inicial (l ->  l = LBound(a)) pero en orden inverso, esto es, n->...->2-> 1Ambas especificaciones son necesarias para el correcto funcionamiento de la función. La segunda por derivar necesariamente de la primera (6) y la primera (el orden de las variables) por ser necesaria para la coherencia de la función y de la función a la que ésta llama (aDel()) (7).

Lo que sí podríamos hacer para "simplificar" el script es prescindir de las variables u y l y utilizar directamente sus referencias de valor, esto es, sustituir For n = u To l Step -1 por For n = UBound(a) To LBound(a) Step -1, con lo que no necesitaríamos más que la variable contador (n en este caso) (8)

El bucle contiene un condicional If que resulta clave para la lógica de la función: sólo si de da la condición x se llama a la función aDel(), lo que equivale a decir que si se da esa condición, y sólo si de da, se elimina la posición y con ella el elemento (dato) que la ocupa. Este x es, en nuestro caso que el dato sea "" (o sea, que la posición de la matriz no contenga ningún dato.

 If Trim(a(n))= "" Then a = aDel(a, n) (9)

Llama la atención que la estructura condicional carezca de la instrucción que la cierra (End If), así como que la consecuencia del cumplimiento de la condición se escriba a continuación de Then. La sintaxis estándar del condicional sería la siguiente:

If Trim(a(n))= "" Then 

    a = aDel(a, n)

End If


NOTAS

(1) Reitero la página de procedencia, [wiki.open-office.es], donde puedes encontrar, además de éstas, otras funciones para trabajar con matrices... y en el sitio muchas más cosas. Excelente contribución.
(2) Al ser una función que llama a otra función, son necesarias ambas para el correcto funcionamiento del script, así que no es posible emplearla de forma aislada. Digo esto para evitar "sorpresas desagradables.
(3) Como ya sabemos, es posible omitir el identificador del modo de pase de datos a la función, ya que en OOo Basic ByRef es el modo por defecto. En consecuencia, la declaración de la función podría ser Function aRemoveEmpty (a()) sin que se altere su funcionamiento. No obstante, me parece pertinente mantener la formulación original, ya que ayuda a comprender mejor el funcionamiento de aRemoveEmpty().
(4) Se usa Long para evitar errores en caso de que la matriz-argumento fuera muy grande, que no suele ser el caso, de ahí que sea perfectamente funcional declarar esas variables como Integer.
(5) El uso de variables en lugar de la formulación directa puede despistarnos a este respecto.
(6) Su ausencia, que implica el uso de su contrario (Step +1) no hace fracasar a la función, pero ésta no obtiene el resultado esperado.
(7) Que trataremos en otra entrada.
(8) Que por tradición se suele identificar como i o como conta. Yo prefiero i. En ese caso la línea de declaración de variables de la función quedaría simplificada a Dim i As Integer
(9) La función Trim() sirve para eliminar los posibles espacios vacíos que pudiera tener el dato que ocupa la posición n de la matriz a() (Trim(a(n)))

No hay comentarios:

Publicar un comentario

Comenta esta entrada