¿Cómo llenar una tabla generada dinámicamente con contenido dinámico?

¿Cómo llenar una tabla generada dinámicamente con contenido dinámico?

¿Cómo genero una tabla dinámicamente mientras la lleno con datos dinámicos?

Ejemplo: digamos que tengo

\def\N{10}

y quiero generar una tabla con \Ncolumnas, donde la celda superior de cada columna contiene el número de la columna, como

\begin{tabular}{|c|c|c|...|c|}
1 & 2 & 3 & ... & N
\end{tabular}

Esto fue lo más cerca que estuve:

\newtoks\cols
\cols={}
\newcounter{i}
\setcounter{i}{1}
\loop
\cols=\expandafter{\the\cols \arabic{i}}
\ifnum\value{i}<\N
\cols=\expandafter{\the\cols &}
\stepcounter{i}
\repeat

\begin{tabular}{|*{\N}{c|}}
\the\cols
\end{tabular}

pero debido a \expandafter, esto me da diez columnas, cada una con un 10.

¿Hay alguna manera de realizar algo así como una expansión parcial? Me gustaría ampliar sólo el \arabic{i}pero por supuesto no el &.

Respuesta1

El problema es la línea:

\cols=\expandafter{\the\cols \arabic{i}}

\colses un registro de token, por lo que \arabic{i}no se expande. Usar un valor adicional \expandaftere imprimir el valor del contador en lugar de \arabicayuda:

\cols=\expandafter{\the\expandafter\cols\the\value{i}}

Ejemplo completo:

\documentclass{article}

\newtoks\cols
\newcounter{i}
\newcount\N

\begin{document}
  \N=10
  \cols={}
  \setcounter{i}{1}
  \loop
    \cols=\expandafter{\the\expandafter\cols\the\value{i}}
  \ifnum\value{i}<\N
    \cols=\expandafter{\the\cols &}
    \stepcounter{i}
  \repeat
  \begin{tabular}{|*{\N}{c|}}
    \the\cols
  \end{tabular}
\end{document}

Resultado

Versión ampliable

El siguiente ejemplo utiliza \numexpr. Se tiene cuidado de conseguir una \ifanidación constante y &no se debe ver demasiado pronto.

\documentclass{article}

\newcount\N

\makeatletter
\newcommand*{\Ncols}{%
  \Ncols@aux{1}%
}
\newcommand*{\Ncols@aux}[1]{%
  \ifnum#1>\N
    \expandafter\@gobble
  \else
    \expandafter\@firstofone
  \fi
  {% 
    \ifnum#1<2 \expandafter\@gobble\fi\Ncols@amp
    #1%
    \expandafter\Ncols@aux\expandafter{\the\numexpr(#1+1)}%
  }%
}
\newcommand*{\Ncols@amp}{&}
\makeatother

\begin{document}

\N=10
\begin{tabular}{|*{\N}{c|}}
\Ncols
\end{tabular}

\end{document}

Resultado

Respuesta2

La respuesta de Heiko.Explicó el problema con su código, cómo resolverlo y también cómo proceder en un estilo diferente usando un bucle de enteros expandible (gracias a \numexpr).

La respuesta de A. Ellettproporciona dos soluciones más usando pgffory pgfkeys.

La respuesta de DJPes un método que utiliza una herramienta externa, aquí Python codemanejada por el poderoso Sagevía sagetex.

Todas estas respuestas necesitan, de una forma u otra, algo de trabajo adicional, como (para aquellas TeX) ocultar la tabulación &en una macro, hacer definiciones globales con \xdef, preparar un registro de lista de tokens o usar varios tipos de TeXcondicionales.

La xintForconstrucción del paquete.herramientas xintes una alternativa (ver¿Cómo iterar sobre una lista separada por comas?) que evita la molestia de esta codificación adicional:

\documentclass{article}
\usepackage{xinttools}
\newcommand{\N}{10}
\begin{document}
% \renewcommand{\N}{<nb of cols>}
\begin{tabular}{*{\N}c}
  \xintFor* #1 in {\xintSeq {1}{\N}}\do {\xintifForFirst{}{&}#1}\\
\end{tabular}
\end{document}

tabular dinámico

La \xintifForFirst{YES}{N0}prueba consiste en insertar una tabulación &solo en la segunda y siguiente celda de la fila dada (aquí solo una fila). La \xintSeqmacro genera una secuencia aritmética de números enteros (por ejemplo {1}{2}{3}{4}). Itera \xintFor* #1 insobre su argumento (su primo sin asterisco \xintForitera sobre una lista separada por comas), dejando #1cada elemento uno tras otro.

El mismo código que el anterior pero usando más bien un LaTeXcontador:

\documentclass{article}
\usepackage{xinttools}
\newcounter{N}
\begin{document}
\setcounter{N}{10}
\begin{tabular}{*{\value{N}}c}
  \xintFor* #1 in {\xintSeq {1}{\value{N}}}\do {\xintifForFirst{}{&}#1}\\
\end{tabular}
\end{document}

Aquí hay ahora un ejemplo más elaborado (ya que utiliza dos bucles anidados) que construye tablas de multiplicar: \numexprse utiliza para multiplicar el índice de fila por el índice de columna.

tabular dinámico 2

Aquí está el código:

\documentclass{article}
\usepackage{xinttools}

\newcommand\MultTable [4]{% 
  % #1, #2 row indices
  % #3, #4 column indices: we need #4-#3+2 columns
  \begin{tabular}{*{\numexpr#4-#3+2\relax}c}
  \hline
  % headerline
  $\times$\xintFor* ##1 in {\xintSeq {#3}{#4}}\do{&\textbf{##1}}\\
  \hline
  % #2-#1+1 rows, ##1=dynamic index of each row, ##2 column index
  \xintFor* ##1 in {\xintSeq {#1}{#2}}\do
     {\textbf{##1}
      \xintFor* ##2 in {\xintSeq {#3}{#4}}\do{&\the\numexpr ##1*##2\relax}
      \\
     }
  \hline
  \end{tabular}%
% efficiency note: one could do \edef\columnindices {\xintSeq {#3}{#4}}
% before the tabular
% and use \columnindices rather \xintSeq {#3}{#4} to avoid it being
% re-computed for each row
}

\begin{document}
\begin{table}[!htbp]
  \centering
  \MultTable {1}{10}{1}{10}
  \caption{Multiplication table}
\end{table}
\begin{table}[!htbp]
  \centering
  \MultTable {123}{132}{91}{98}
  \caption{Multiplication table}
\end{table}
\end{document}

Como usamos \xintFor*dentro de la definición de un LaTeXcomando de usuario, necesitábamos duplicar #para evitar confusión entre el ##1bucle y #1ser el primer parámetro del comando.

Respuesta3

Si no le importa aprender un poco de Python, el sagetexpaquete puede manejar tablas dinámicas fácilmente; después de todo, Python es un lenguaje poderoso. La documentación para sagetex esaquíy, en ejemplo.pdf, construyen el Triángulo de Pascal. Aquí está el código para algo más parecido a lo que solicitó; la primera fila es del 1 al N:

\documentclass{article}
\usepackage{sagetex}
\pagestyle{empty}
\begin{document}
\begin{sagesilent}
N = 5
M = 4
output = r"\begin{tabular}{"
for i in range(0,N):
    output += r"|c"
output += r"|}"
for j in range(0,M):
    for i in range(0,N-1):
        output += r"%d & "%((j+1)*(i+1))
    output += r"%d \\"%(N*(j+1))
output += r"\end{tabular}"
\end{sagesilent}
Here's the output:\\\\
\sagestr{output}
\end{document}

ingrese la descripción de la imagen aquí

Con la cantidad limitada de Python que necesitas aprender, me imagino que probablemente sea más fácil que programar en TeX. Necesita saber: los bucles for no incluyen el último valor enumerado en el rango y r es para cadenas sin formato y evita problemas que puedan surgir al tener caracteres como una barra invertida en su cadena. Finalmente, %d es para insertar números enteros, %f para flotante y %s para cadena. El sagesilententorno escribe el código real que luego se inserta mediante un archivo sagestr.

Respuesta4

Esto se puede hacer de varias maneras, como ya lo sugieren los comentarios y otras respuestas. Aquí hay dos soluciones que usan pgffory pgfkeys.

Esta primera solución funciona sin utilizar claves:

\documentclass{article}
\usepackage{pgffor}
\usepackage{etoolbox}

\makeatletter
\newcommand\aeDynamicTable{\ae@dynamicTable}
\def\ae@dynamicTable[#1]#2{%%
  \let\ae@table@content\relax%%
  \def\ae@new@column{&}
  \def\ae@row{0}%%
  \foreach \x in {1,...,#2}
    {%%
      \xdef\ae@row{\number\numexpr\ae@row+1\relax}%%
      \ifx\relax\ae@table@content
        \xdef\ae@table@content{\noexpand\@arabic{\x}}%
      \else
        \xdef\ae@table@content{\expandonce{\ae@table@content} \noexpand\@arabic{\x}}%%
      \fi
      \ifnum\ae@row=#1\relax
        \xdef\ae@row{0}%%
        \def\ae@new@line{\\}%%
        \def\ae@new@column{}%%
      \else
        \def\ae@new@line{}%%
        \def\ae@new@column{&}%%
      \fi
      \ifnum\x=#2\relax
        \def\ae@new@line{}%%
        \def\ae@new@column{}%%
      \fi
      \xdef\ae@table@content{\expandonce{\ae@table@content} \expandonce{\ae@new@column} \expandonce{\ae@new@line}}%
    }%%
    \begin{tabular}{|*{#1}{c|}}
      \ae@table@content 
    \end{tabular}%%
  }

\makeatother

\begin{document}

\aeDynamicTable[3]{5}

\aeDynamicTable[10]{35}

\end{document}

Este segundo ejemplo realiza la misma tarea usando claves:

\documentclass{article}
\usepackage{pgffor}
\usepackage{pgfkeys}
\usepackage{etoolbox}

\makeatletter
\def\ae@col@limit{}
\def\ae@max@cells{}
\pgfkeys{/ae/dynamic/table/.cd,
  cols/.store in=\ae@col@limit,
  cells/.store in=\ae@max@cells,
}

\newcommand\aeDynamicTable{\ae@dynamicTable}
\def\ae@dynamicTable#1{%%
  \pgfkeys{/ae/dynamic/table/.cd,#1}%% 
  \let\ae@table@content\relax%%
  \def\ae@new@column{&}
  \def\ae@col{0}%%
  \foreach \x in {1,...,\ae@max@cells}
    {%%
      \xdef\ae@col{\number\numexpr\ae@col+1\relax}%%
      \ifx\relax\ae@table@content
        \xdef\ae@table@content{\noexpand\@arabic{\x}}%
      \else
        \xdef\ae@table@content{\expandonce{\ae@table@content} \noexpand\@arabic{\x}}%%
      \fi
      \ifnum\ae@col=\ae@col@limit\relax
        \xdef\ae@col{0}%%
        \def\ae@new@line{\\}%%
        \def\ae@new@column{}%%
      \else
        \def\ae@new@line{}%%
        \def\ae@new@column{&}%%
      \fi
      \ifnum\x=\ae@max@cells\relax
        \def\ae@new@line{}%%
        \def\ae@new@column{}%%
      \fi
      \xdef\ae@table@content{\expandonce{\ae@table@content} \expandonce{\ae@new@column} \expandonce{\ae@new@line}}%
    }%%
    \begin{tabular}{|*{\ae@col@limit}{c|}}
      \ae@table@content 
    \end{tabular}%%
  }

\makeatother

\begin{document}

\aeDynamicTable{cols=3,cells=5}

\aeDynamicTable{cols=10,cells=35}

\end{document}

En cualquier caso las tablas resultantes son:

ingrese la descripción de la imagen aquí

información relacionada