jueves, 12 de enero de 2023

LAMBDA: Completar Fechas

Una situación con la que me encuentro a menudo es trabajar con rangos de datos, basados en rangos temporales, en los que NO existen ciertas fechas, i.e., trabajamos con listados con saltos de fechas.
Esto se convierte en un problema cuando hay que cruzarlos con otros listados en los que si existe la totalidad de las fechas.
LAMBDA: Completar Fechas


Veremos un par de soluciones directas para el caso en que NO existieran fechas repetidas, y solo pretendieramos completar los huecos entre fechas....
Una primera opción se basa en el empleo de la función APILARH y BYROW.
Así en F5 podemos escribir:
=LET(rDatos;$B$5:$D$17;
fechas;INDICE(rDatos;0;1); Pais;INDICE(rDatos;0;2);Importes;INDICE(rDatos;0;3);
desde;MIN(fechas);hasta;MAX(fechas);
rFechasN;SECUENCIA(hasta-desde+1;;desde;1);
rPaisN;BYROW(rFechasN;LAMBDA(vFecha;BUSCARX(vFecha;fechas;Pais;"")));
rImporteN;BYROW(rFechasN;LAMBDA(vFecha;BUSCARX(vFecha;fechas;Importes;"")));
APILARH(rFechasN;rPaisN;rImporteN))
Observa en la imagen anterior cómo se han completado las fechas faltantes, pero como falla al recuperar fechas repetidas...
La lectura de la función es simple, ya que comenzamos declarando nuestras variables de trabajo... que basicamente son el rango completo origen y la definición de las columnas/campos a recuperar.
...
   rDatos;$B$5:$D$17;
fechas;INDICE(rDatos;0;1); Pais;INDICE(rDatos;0;2);Importes;INDICE(rDatos;0;3);
desde;MIN(fechas);hasta;MAX(fechas);
...

También, con SECUENCIA, obtenemos un rango de fechas completo.
...
    rFechasN;SECUENCIA(hasta-desde+1;;desde;1);
    ...

En el siguiente paso realizamos búsquedas de información para cada fecha del rango completado; la función BYROW nos ayudará en esto, recorriendo cada fecha y realizando una búsqueda (con BUSCARX) sobre el rango original.
...
    rPaisN;BYROW(rFechasN;LAMBDA(vFecha;BUSCARX(vFecha;fechas;Pais;"")));
rImporteN;BYROW(rFechasN;LAMBDA(vFecha;BUSCARX(vFecha;fechas;Importes;"")));
    ...

Finalizamos 'juntando' todo con APILARH
...
    APILARH(rFechasN;rPaisN;rImporteN))


Otra opción, de las muchas existentes, sería emplear la función ARCHIVOMAKEARRAY, como podemos ver en J5:
=LET(rDatos;$B$5:$D$17;
fechas;INDICE(rDatos;0;1);
desde;MIN(fechas);hasta;MAX(fechas);
rFechasN;SECUENCIA(hasta-desde+1;;desde;1);
nFilas;FILAS(rFechasN);nCols;COLUMNAS(rDatos);
rDatosN;ARCHIVOMAKEARRAY(nFilas;nCols;LAMBDA(f;c;SI(c>1;BUSCARX(INDICE(rFechasN;f);fechas;INDICE(rDatos;0;c);"");INDICE(rFechasN;f))));
rDatosN)

Con un comienzo muy similar a la fórmula anterior, donde se declaran las variables que vamos a necesitar:
...
   rDatos;$B$5:$D$17;
fechas;INDICE(rDatos;0;1);
desde;MIN(fechas);hasta;MAX(fechas);
rFechasN;SECUENCIA(hasta-desde+1;;desde;1);
nFilas;FILAS(rFechasN);nCols;COLUMNAS(rDatos);
...

La diferencia es que en este caso, para llegar a idéntico resultado, el cálculo de los elementos de nuestra matriz resultante única, se contruye con ARCHIVOMAKEARRAY, finalizando así el proceso...
:
...rDatosN;ARCHIVOMAKEARRAY(nFilas;nCols;LAMBDA(f;c;SI(c>1;BUSCARX(INDICE(rFechasN;f);fechas;INDICE(rDatos;0;c);"");INDICE(rFechasN;f))))

Nuevamente se emplea como función de búsqueda BUSCARX, por lo que el caso de fechas repetidas NO está contemplado...

¿Y entonces cómo solucionamos el caso extremo de tener saltos de fechas y además fechas repetidas??.
Veamos una posible solución en N5 empleando APILARV, FILTRAR o BYROW entre otras:
  =LET(rDatos;$B$5:$D$17;
fechas;INDICE(rDatos;0;1);
desde;MIN(fechas);hasta;MAX(fechas);
rFechasN;SECUENCIA(hasta-desde+1;;desde;1);
rNOCoincidentes;LET(criterio;BYROW(rFechasN;LAMBDA(vFecha;NO(SI.ERROR(COINCIDIR(vFecha;fechas;0)>0;FALSO))));FILTRAR(rFechasN;criterio));
ORDENAR(SI.ERROR(APILARV(rDatos;rNOCoincidentes);"")))

Como en los casos anteriores el inicio de la fórmula es el mismo, declaro variables (básicamente las mismas):
...
   rDatos;$B$5:$D$17;
fechas;INDICE(rDatos;0;1);
desde;MIN(fechas);hasta;MAX(fechas);
rFechasN;SECUENCIA(hasta-desde+1;;desde;1);
...

Para continuar con el cálculo de las 'fechas faltantes':
... rNOCoincidentes;LET(criterio;BYROW(rFechasN;LAMBDA(vFecha;NO(SI.ERROR(COINCIDIR(vFecha;fechas;0)>0;FALSO))));FILTRAR(rFechasN;criterio));...

donde la función FILTRAR nos permite obtener el listado de fechas NO existentes, a partir de un vector de VERDADEROS y FALSOS generado con BYROW.
La fórmula termina aplicando APILARV para unir los datos originales (la totalidad!!) con las fechas que faltaban para completar el rango temporal...

Como siempre abierto a aprender y comentar alguna idea alternativa para dar solución al problema ;-)

No hay comentarios:

Publicar un comentario

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