martes, 17 de mayo de 2022

VBA: JOIN & TRANSPOSE mejor juntos

Quizá en alguna ocasión hayas requerido recuperar datos de la hoja de cálculo y tratarlos como una cadena de texto, y seguramente en algún momento lo hayas necesitado trabajar desde una Array...
Si has contestado afirmativamente en ambos casos, este artículo te ayudará.

Es probable conozcas la función JOIN(sourcearray, [ delimiter ]):
función interesante que propone la posibilidad de retornar una cadena creada mediante la combinación de varias subcadenas de una matriz/array.
Con dos sencillos argumentos:
sourcearray (obligatorio): Debe ser una matriz unidimensional que contenga las subcadenas que se van a combinar.
delimiter (opcional): carácter que se utilizará para separar las subcadenas en la cadena devuelta.
Si se omite, se utiliza el carácter de espacio (" ").
Si delimitador es una cadena de longitud cero (""), se concatenan todos los elementos de la lista sin delimitadores.

Pinta bien... parece asemejarse a funciones de la hoja de cálculo como UNIRCADENAS, o CONCAT.

Pero hay trampa con ella. Veamos un ejemplo.
Partimos de un listado de algunos países, en forma de tabla, en nuestra hoja de cálculo... llamada 'TblPAIS'
VBA: JOIN & SPLIT mejor juntos

Asi que un primer intento podría ser generar una macro en un módulo estándar:
Sub IntentoJOIN()
Dim arrPaises() As String

arrPaises = Join(Range("TblPAIS"), ",")

Debug.Print arrPaises
End Sub

Donde intentamos, sin éxito, cargar en nuestra variable-matriz 'arrPaises' los elementos del rango 'TblPAIS' para que conformen una cadena de texto...
Puedes intentar cuantas combinaciones desees:
Dim arrPaises() As Variant
Dim arrPaises As String
etc
todas ellas acaban con el mismo mensaje: No coinciden los tipos

¿Qué ocurre?, ¿qué estoy haciendo mal?.
Bien, la cosa tiene que ver con los tipos de datos admitidos por los argumentos de JOIN... en concreto el argumento 'sourcearray', que especificamente indica debe ser una array unidimensional de subcadenas.. y en el ejemplo le he asignado un Range!.

Veamos pues una posible, y simple, solución. Modifiquemos nuestra macro, quedando ahora funcional:
Sub IntentoJOIN()
'defino la futura cadena de texto resultado
Dim strPaises As String

'y aplicamos después de Transponer, y retornar la cadena de texto buscada...
strPaises = Join(Application.Transpose(Range("TblPAIS").Value), ",")

'devolvemos el resultado a la ventana de inmediato
Debug.Print strPaises
End Sub
''''''''''''''''''''
'o alternativamente, si prefieres más claridad
'''''''''''''''''''''
Sub IntentoJOIN_v2()
'defino una array, y la futura cadena de texto resultado
Dim arrPaises As Variant, strPaises As String
'en la primera, como tipo Variant, cargamos los datos de la hoja de cálculo
arrPaises = Range("TblPAIS").Value

'y ya como array, sí podemos trabajar con JOIN, y retornar la cadena de texto buscada...
strPaises = Join(Application.Transpose(arrPaises), ",")

'devolvemos el resultado a la ventana de inmediato
Debug.Print strPaises
End Sub

:OO así de simple.
MUY IMPORTANTE aplicar 'Application.Transpose' para disponer de esa matriz unidimensional requerida.

Una alterantiva, para gustos los colores, es generar la array necesaria empleando una combinación de SPLIT y JOIN... algo retorcida ;-D
La función Split(expression, [ delimiter, [ limit, [ compare ]]]) es otra de esas funciones de uso habitual que seguramente no nos hayamos detenido nunca a analizar.
La función devuelve una matriz/array de base cero unidimensional que contiene un número especificado de subcadenas.
Recalquemos: UNIDIMENSIONAL.
Asi nuestro procedimiento podría ser:
Sub IntentoSPLIT_JOIN()
'defino una array y la cadena de texto final
Dim arrPaises() As String, strPaises As String
'en la primera, como tipo String , cargamos los datos de la hoja de cálculo
arrPaises = Split(Join(Application.Transpose(Range("TblPAIS").Value), "|"), "|")

'utilizo de nuevo JOIN para concatenar los elementos de la array obtenida
'(ya he dicho que es retorcido) :D
strPaises = Join(arrPaises, ",")

'devolvemos el resultado a la ventana de inmediato
Debug.Print strPaises
End Sub


recuerda pues estas DOS líneas... te sacarán del apuro en más de una ocasión
Sub JOIN_TRANSPOSE()
Dim strPaises As String
strPaises = Join(Application.Transpose(Range("TblPAIS").Value), ",")

Debug.Print strPaises
End Sub


Nota: He leído y leído por diferentes sitios en busca de documentación de Transpose, pero a parte de la referida a la función de la hoja de cálculo, poco más :'(
Pero sin duda es fundamental para 'convertir' rangos directamente a Arrays unidimensionales... requeridas, como hemos visto, en distintas funciones.

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.