Intercambio de datos entre matrices desiguales.
Aunque en parte ya tratamos algo de este tema en la [entrada anterior] la "solución" encontrada ni es la única ni la mejor, por lo que se puede considerar que el paso de datos de una matriz-fuente (de datos) a una segunda matriz receptora de diferente tamaño que la primera sigue estando sin solución, al menos sin la solución adecuada.
De hecho, lo que hicimos antes fue partir de una matriz no dimensionada y redimensionada en el momento preciso y con el suficiente y apriorístico conocimiento del contenido de la matriz-fuente: queremos pasar un segmento conocido de datos (tamaño, inicio y fin) de la matriz-fuente a una segunda matriz. La solución fue relativamente sencilla (1) ya que contábamos con los datos necesarios, pero en la mayoría de las ocasiones no se van a dar estas condiciones tan favorables.
Para hacer más complicada la cosa hay que decir que la instrucción ReDim presenta una característica que la hace poco flexible: borra el contenido de la matriz que es redimensionada. Existe otra instrucción cuyo objetivo es precisamente mantener (Preserve, preservar) dicho contenido, pero no cumple con ese objetivo, así que Redim mRecurso(4) tiene el mismo efecto que Redim Preserve mRecurso(4), una matriz dimensionada convenientemente, pero vacía.
Por suerte contamos con funciones desarrolladas por la comunidad LibreOffice que nos ayudan a trabajar con matrices (2), así que vamos a mostrar (y explicar) algunas soluciones que me han parecido de especial interés.
Un primer ejemplo o forma de actuar, puede ser cuando nos interesa pasar a la matriz-recurso determinados datos de la matriz-fuente, concretamente aquellos que cumplan cierta condición. En este caso redimensionar la matriz-recurso no nos resuelve nada (3), ya que inicialmente podemos partir de que sea de igual dimensión que la matriz-fuente, así que podemos emplear el siguiente procedimiento: pasamos los datos de mFuente() a mRecurso() por la vía más fácil (mRecurso() = mFuente()) y después aplicamos a los datos de mFuente() la condicionalidad que deseemos. Por ejemplo:
Sub Matices4Dim mFuente () As Integer, mRecurso() As Integer, i As IntegermFuente = Array(11,24,14,38,6,32,27,9,46)mRecurso() = mFuente()MsgBox "Visualizar datos de mRecurso()"For i = LBound(mRecurso()) To UBound(mRecurso())MsgBox "Posición " & i & " Valor " & mRecurso(i)Next'Modificamos la matriz-recursoFor i = LBound(mRecurso()) To UBound(mRecurso())If mRecurso(i) < 21 ThenmRecurso(i) = ""End IfMsgBox "Posición " & i & " Valor " & mRecurso(i)NextEnd Sub
En este caso, disponemos de una colección de datos recogida en mFuente() (4) y queremos pasar a mRecurso() sólo aquellos que sean superiores a 20, así que...
- Asignamos a mRecurso() el contenido de mFuente() (mRecurso() = mFuente())
- Modificamos mRecurso() de forma que se mantengan los valores que cumplen la condición, mientras que el resto los igualamos a "" (vacío). Para ello empleamos un bucle y un condicional simple anidado (If mRecurso(i) < 20 Then -> mRecurso(i) = "" -> End If).
- El resultado que obtenemos es una matriz mRecurso() que mantiene la dimensión original y que contiene posiciones sin dato ("") y el resto valores superiores a 20, heredados de la mFuente().
De hecho disponemos de dos soluciones: eliminar los elementos vacíos de la matriz-recurso (5) o ir añadiendo a esta matriz los elementos (datos) que nos interesen de la matriz-fuente y sólo éstos (6). Para ambas propuestas disponemos de funciones que realizan el trabajo.
Expongo a continuación el código de la primera solución:
Sub Matices4Dim mFuente () As Integer, mRecurso() As Integer, i As IntegermFuente = Array(11,24,14,38,6,32,27,9,46)mRecurso() = mFuente()'Modificamos la matriz-recurso para convertir en "" los valores'originales inferiores al valor criterio (<21)MsgBox "Visualizar datos de mRecurso() después del borrado de las posiciones vacías"For i = LBound(mRecurso()) To UBound(mRecurso())If mRecurso(i) < 21 ThenmRecurso(i) = ""End IfNext'LLamamos a la función que elimina las posiciones ""mRecurso()= aRemoveEmpty (mRecurso())'... y visualizamos el contenido de la matriz resultante (redimensionada)For i = LBound(mRecurso()) To UBound(mRecurso())MsgBox "Posición " & i & " Valor " & mRecurso(i)NextEnd Sub' FUNCIONES -------------------------------------------------------------------'Función 1. Recorre la matriz pasada, identifica los elementos vacíos'y solicita a la función aDel() su eliminación.Function aRemoveEmpty ( ByRef a() )Dim n As Long, u As Long, l As Longu = UBound( a )l = LBound( a )For n = u To l Step -1If Trim(a(n))= "" Then a = aDel( a, n ) 'Llama a la función aDel() si se da la condición de ""NextaRemoveEmpty = aEnd Function'Función 2. Borra las posiciones de la matriz pasada por el función aRemoveEmpty ()Function aDel( ByRef a(), nIni As Long, Optional nFin As Long )Dim aTmp(), u As Long, r As Long, n As LongIf IsMissing( nFin ) Then nFin = nIniOn Local Error GoTo error_aDelu = UBound(a())If nIni = -1 Then ' clave especial, borrar el último elementoReDim aTmp(u-1)For n=0 To u-1aTmp(n)=a(n)NextElseReDim aTmp(u-(nFin-nIni)-1)For n=0 To nIni-1aTmp(n)=a(n)Nextr=nFor n=nFin+1 To uaTmp(r)=a(n)r=r+1NextEnd Ifa() = aTmp()aDel = a()Exit Functionerror_aDel: ' sólo tiene un elemento o no se ha inicializado el arrayReDim a()aDel = a()End Function
Observa que, en este caso, necesitamos dos funciones para conseguir el objetivo deseado: que la matriz-recurso sólo tenga la dimensión ajustada a los datos que contiene (y no de la matriz-fuente). La primera de estas funciones (aRemoveEmpty()) [ver aquí] llama a la segunda (aDel()) [ver aquí]. Esa primera lo que hace es señalar qué elementos de la matriz-recurso deben ser borrados y la segunda procede a eliminarlos. La complejidad de su formulación no queda explicada con lo dicho antes (sólo nos informa del funcionamiento general de ambas funciones), pero hacerlo excede lo conveniente para esta entrada, así que remito a los enlaces anteriores para cada una de ellas.
La segunda solución resulta ser más simple, aunque también su función se explica en [esta entrada].
Sub Matices6Dim mFuente() As Integer, mRecurso() As Integer, i As Integer
'Creamos la matriz-origen (mFuente()) mediante Array()mFuente = Array(11,24,14,38,6,32,27,9,46)'Pasamos valores a la función aAdd() condicionado al cumplimiento de un criterio:'que el valor del elemento de la matriz-origen sea superior a 20For i = LBound(mFuente ()) To UBound(mFuente ())If mFuente(i) > 20 ThenmRecurso() = aAdd(mRecurso(), mFuente(i))End IfNext'Visualizamos el contenido de la matriz resultante (redimensionada)MsgBox "Datos después del borrado de vacíos"For i = LBound(mRecurso()) To UBound(mRecurso())MsgBox "Posición " & i & " Valor " & mRecurso(i)NextEnd Sub'FUNCION ---------------------------------------------------------------'Agrega un elemento a un array y lo llena con xValorFunction aAdd( ByRef a(), ByVal xValor )Dim u As Longu = UBound( a ) + 1ReDim Preserve a( u )a(u) = xValoraAdd = aEnd Function
Puedes comprobar que tanto el script como la función (ahora sólo una) son más sencillos y contienen menos líneas de código, por lo que parece que esta segunda solución gana a la primera en simplicidad. No obstante ambas son opciones interesantes que requieren un estudio más detenido. sólo cuando lo concluyamos estaremos en disposición de tomar la decisión de hacer uso de una o de otra alternativa.
De momento las dos quedan disponibles, aunque pendientes de explicación. Tú ya puedes trabajar con ellas (en este caso copiándolas directamente desde el texto de la entrada) e ir estudiándolas.
NOTAS
(1) Ver en la [entrada anterior] el script que posibilita esta solución.
(2) Las funciones que muestro en esta entrada proceden de wiki.open-office.es. En esta wiki puedes encontrar soluciones interesantes a muchos problemas; es parte de las ventajas de la colaboración, característica especialmente destacable en el mundo del software libre.
(3) Lo que no quiere decir que no la usemos, pero en según qué circunstancias ni siquiera será necesario, como en el ejemplo que mostramos en la entrada.
(4) (aquí los pasamos mediante Array(), pero es una cuestión secundaria.
(5) Lo que presupone que previamente habremos cargado en ella los datos de la matriz-fuente.
No hay comentarios:
Publicar un comentario
Comenta esta entrada