Desglose de asientos contables con unpivot y generación automática de contrapartidas

Interesante problema planteado por Juan en el grupo: tiene una tabla de asientos contables en formato horizontal (cada fila contiene cuenta, concepto y varias columnas de importes por tipo de asiento) y necesita convertirla en un listado vertical tipo libro diario, generando además las contrapartidas automáticas (la cuenta 572, caja, con el importe en negativo).

El reto tiene dos partes. La primera: dado un rango con columnas Cuenta, Concepto, Fecha e Importe, generar una fila adicional por cada asiento con la cuenta de contrapartida (572) y el importe invertido, intercalándola justo debajo del asiento original. La segunda: cuando la tabla tiene múltiples columnas de importes (varios asientos por fila) con cabeceras de tipo de asiento y conceptos en filas superiores, hacer el unpivot completo y asignar cada concepto a su asiento correspondiente.

Primera parte: contrapartidas con ENCOL + AJUSTARFILAS

Nacho propone una solución con LET que apila horizontalmente los datos originales junto con las contrapartidas generadas, y luego usa la técnica de entrelazar matrices con ENCOL + AJUSTARFILAS para intercalar las filas:

``
=LET(
_datos; B5:E17;
AJUSTARFILAS(
ENCOL(
APILARH(
_datos;
SECUENCIA(FILAS(_datos); ; 572; 0);
ELEGIRCOLS(_datos; 2; 3);
TOMAR(_datos; ; -1) * -1
)
);
4
)
)
`

La clave es APILARH para poner lado a lado los datos originales y las contrapartidas (4 columnas + 4 columnas), luego ENCOL los convierte en una sola columna vertical, y AJUSTARFILAS(...; 4) los redistribuye en filas de 4 columnas. Como los datos originales y las contrapartidas estaban lado a lado, al "enrollar y desenrollar" quedan perfectamente intercalados.

Miki aporta dos variantes con EXPANDIR y ELEGIRCOLS:

`
=LET(
a; B5:E17;
b; APILARH(
EXPANDIR(572; FILAS(a); 1; 572);
ELEGIRCOLS(a; 2; 3);
-ELEGIRCOLS(a; -1)
);
AJUSTARFILAS(ENCOL(APILARH(a; b)); COLUMNAS(a))
)
`

Y una segunda versión que filtra las filas donde la cuenta ya es 572 (para no duplicar contrapartidas):

`
=LET(
a; B5:E17;
b; SI(
ELEGIRCOLS(a; 1) <> "572";
APILARH(
EXPANDIR(572; FILAS(a); 1; 572);
ELEGIRCOLS(a; 2; 3);
-ELEGIRCOLS(a; -1)
)
);
AJUSTARFILAS(ENCOL(APILARH(a; b)); COLUMNAS(a))
)
`

Hugo lo resuelve en una sola línea sin LET, usando una constante matricial {1\0\0} para seleccionar qué columnas replicar:

`
=AJUSTARFILAS(ENCOL(APILARH(B5:E17; APILARH(SI({1\0\0}; 572; B5:D17); -E5:E17))); 4)
`

Muy compacta: SI({1\0\0}; 572; B5:D17) sustituye la primera columna por 572 y mantiene las otras dos, luego le concatena el importe negado. Mismo resultado, sin variables intermedias.

Segunda parte: unpivot con conceptos y tipos de asiento

Juan plantea una extensión más compleja: la tabla tiene múltiples columnas de importes agrupadas bajo cabeceras de tipo de asiento (fila 1) y conceptos (fila 2), con celdas combinadas. Necesita hacer el unpivot completo asignando cada concepto a su columna.

Miki construye una fórmula con SCAN para propagar las cabeceras combinadas, y SI.CONJUNTO para extraer el concepto correcto según el tipo de asiento:

`
=LET(
_c1; SCAN(""; D1:N1; LAMBDA(a; v; SI(v = ""; a; v)));
_c2; D2:N2;
m; D3:N14;
F; LAMBDA(x; ENCOL(SI.CONJUNTO(m <> ""; x); 2));
a; APILARH(F(A3:A14); F(B3:B14); F(C3:C14); F(_c1); F(_c2); F(m));
SI.CONJUNTO(
ELEGIRCOLS(a; 4) = "Tipo Asiento 3";
APILARH(ELEGIRCOLS(a; 1; 2); ESPACIOS(TEXTODESPUES(ELEGIRCOLS(a; 3); "-")); ELEGIRCOLS(a; -2; -1));
ELEGIRCOLS(a; 4) = "Tipo Asiento 4";
APILARH(ELEGIRCOLS(a; 1; 2); ESPACIOS(TEXTODESPUES(ELEGIRCOLS(a; 3); "-")); ELEGIRCOLS(a; -2; -1));
ELEGIRCOLS(a; 4) <> "Tipo Asiento 3";
APILARH(ELEGIRCOLS(a; 1; 2); ESPACIOS(TEXTOANTES(ELEGIRCOLS(a; 3); "-"; ; ; ; ELEGIRCOLS(a; 3))); ELEGIRCOLS(a; -2; -1))
)
)
`

Destaca el uso de SCAN para "rellenar" las cabeceras de celdas combinadas y la función F definida como LAMBDA reutilizable para hacer el unpivot de cada columna auxiliar.

Lourdes propone un enfoque diferente con REDUCE + APILARV para iterar sobre las filas de asientos y construir el resultado fila a fila:

`
=LET(
m; REDUCE(
{"Fecha"; "CONCEPTO"; "Cuenta"; "Importe"};
C3:C4;
LAMBDA(i; x;
APILARV(i;
SI({1; 0; 0; 0};
@+x:B4;
TRANSPONER(
APILARV(0;
INDICE(DIVIDIRTEXTO(x; ; "/");
SCAN(0; SI.ERROR(--DERECHA(D1:R1); ); MAX)
);
D2:R2;
TOMAR(x:R4; 1; -15)
)
)
)
)
)
);
FILTRAR(m; DROP(m; ; 3) <> 0)
)
`

Usa DIVIDIRTEXTO con "/" como separador para extraer los conceptos, y SCAN + MAX para identificar los grupos de columnas.

La técnica clave: entrelazar matrices

Todas las soluciones de la primera parte comparten el mismo patrón: ENCOL + AJUSTARFILAS. ENCOL aplana dos matrices apiladas horizontalmente en una sola columna, y AJUSTARFILAS` las redistribuye con el ancho original. El efecto es que las filas de ambas matrices quedan intercaladas, como barajar dos mazos de cartas. Es una técnica muy potente para cualquier situación donde necesites "insertar" filas calculadas entre las originales.

Convertir una tabla de asientos contables en formato horizontal a un listado vertical tipo libro diario es una de esas tareas que parecen simples hasta que te sientas a hacerlas. Y si además tienes que generar las contrapartidas automáticas, la cosa se complica. Juan planteó exactamente este reto en la comunidad y las soluciones que salieron enseñan una técnica que sirve para muchísimo más que contabilidad.

El problema

La tabla de partida tiene una fila por asiento con las columnas Cuenta, Concepto, Fecha e Importe. Lo que se necesita es un listado donde, justo debajo de cada asiento, aparezca su contrapartida: la cuenta 572 (caja) con el mismo concepto y fecha, pero con el importe invertido.

Es decir, no basta con añadir filas al final. Hay que intercalarlas entre las originales, alternando una y una. Y ahí es donde la mayoría se atasca.

La técnica clave: entrelazar matrices

La solución de Nacho se apoya en un patrón que conviene memorizar: ENCOL seguido de AJUSTARFILAS.

=LET(
    _datos; B5:E17;
    AJUSTARFILAS(
        ENCOL(
            APILARH(
                _datos;
                SECUENCIA(FILAS(_datos); ; 572; 0);
                ELEGIRCOLS(_datos; 2; 3);
                TOMAR(_datos; ; -1) * -1
            )
        );
        4
    )
)

El razonamiento es elegante. Primero APILARH coloca lado a lado los datos originales (4 columnas) y las contrapartidas construidas (otras 4 columnas): la cuenta 572 repetida con SECUENCIA de paso 0, el concepto y la fecha copiados con ELEGIRCOLS, y el importe negado con TOMAR sobre la última columna.

Después ENCOL aplana ese bloque de 8 columnas en una única columna vertical, leyendo fila a fila. Y AJUSTARFILAS(...; 4) lo vuelve a plegar en bloques de 4 columnas.

El efecto es el de barajar dos mazos de cartas: como original y contrapartida iban pegados en la misma fila, al enrollar y desenrollar quedan alternados automáticamente. Sin bucles, sin columnas auxiliares.

Variantes de la comunidad

Miki propone la misma idea usando EXPANDIR para generar la columna de cuentas 572 y ELEGIRCOLS con índice negativo para el importe:

=LET(
    a; B5:E17;
    b; APILARH(
        EXPANDIR(572; FILAS(a); 1; 572);
        ELEGIRCOLS(a; 2; 3);
        -ELEGIRCOLS(a; -1)
    );
    AJUSTARFILAS(ENCOL(APILARH(a; b)); COLUMNAS(a))
)

Fíjate en el detalle de COLUMNAS(a) como segundo argumento de AJUSTARFILAS: así la fórmula se adapta sola si la tabla cambia de ancho.

Miki añade además una segunda versión que evita duplicar contrapartidas cuando la cuenta ya es la 572, envolviendo el bloque b en un SI que comprueba NO(ELEGIRCOLS(a; 1) = "572"). Solo genera contrapartida para las filas que la necesitan.

John lo condensa en una sola línea sin LET, apoyándose en una constante matricial horizontal de tres elementos (un uno seguido de dos ceros) dentro de un SI: donde hay uno, coloca el 572; donde hay cero, mantiene la columna original. Después le concatena el importe negado y aplica el mismo ENCOL y AJUSTARFILAS de 4 columnas. Mismo resultado, cero variables intermedias.

Segunda parte: el unpivot completo

Juan sube la apuesta: la tabla real tiene varias columnas de importes agrupadas bajo cabeceras de tipo de asiento, con celdas combinadas y una fila de conceptos.

Miki lo resuelve propagando las cabeceras combinadas con SCAN, que arrastra el último valor no vacío hacia la derecha, y define una LAMBDA reutilizable dentro de LET para hacer el unpivot de cada columna auxiliar. Después usa SI.CONJUNTO para extraer el concepto correcto según el tipo de asiento, con TEXTOANTES y TEXTODESPUES sobre el guion separador.

Lourdes ataca por otro lado: REDUCE con APILARV para construir el resultado fila a fila, usando DIVIDIRTEXTO con la barra como separador para trocear los conceptos y SCAN con MAX para identificar a qué grupo de columnas pertenece cada importe.

Funciones clave

  • ENCOL — aplana una matriz en una sola columna, leyendo por filas
  • AJUSTARFILAS — repliega una columna en una matriz del ancho que le indiques
  • APILARH — pega matrices lado a lado
  • EXPANDIR y SECUENCIA — dos formas de generar una columna con un valor repetido
  • ELEGIRCOLS — selecciona columnas por posición, admite índices negativos desde el final
  • SCAN — ideal para rellenar huecos de cabeceras combinadas

Conclusión

El patrón ENCOL mas AJUSTARFILAS no va de contabilidad: sirve siempre que necesites insertar filas calculadas entre las originales. Duplicar registros, generar líneas de detalle, alternar dos tablas... la mecánica es la misma.

Casos como este nacen de problemas reales de trabajo, y en la comunidad de InflueXcel suelen aparecer tres o cuatro enfoques distintos para el mismo reto. Comparar las soluciones enseña más que memorizar una.

Más casos con estas funciones

Más contenido de Excel en InflueXcel