Como preencher uma tabela gerada dinamicamente com conteúdo dinâmico?

Como preencher uma tabela gerada dinamicamente com conteúdo dinâmico?

como faço para gerar um tabular dinamicamente enquanto o preencho com dados dinâmicos?

Exemplo: digamos que eu tenha

\def\N{10}

e quero gerar uma tabela com \Ncolunas, onde a célula superior de cada coluna contenha o número da coluna, como

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

Este foi o mais próximo que cheguei:

\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}

mas devido ao \expandafter, isso me dá dez colunas, cada uma contendo 10.

Existe uma maneira de realizar algo como uma expansão parcial? Eu gostaria de expandir apenas o, \arabic{i}mas é claro que não o &.

Responder1

O problema é a linha:

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

\colsé um registro de token, portanto \arabic{i}não é expandido. Usar um adicional \expandaftere imprimir o valor do contador em vez de \arabicajuda:

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

Exemplo 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

Versão expansível

O exemplo a seguir usa e-TeX \numexpr. É tomado cuidado para conseguir um \ifninho constante e &não deve ser visto muito cedo.

\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

Responder2

A resposta de Heikoexplicou o problema com seu código, como resolvê-lo e também como proceder em um estilo diferente usando um loop inteiro expansível (graças a \numexpr).

Resposta de A.Ellettfornece mais duas soluções usando pgffore pgfkeys.

Resposta do DJPé um método que utiliza uma ferramenta externa, aqui Python codecontrolada pelo poderoso Sagevia sagetex.

Todas essas respostas precisam, de uma forma ou de outra, de algum trabalho extra, como (para aquelas TeX) ocultar a tabulação &em uma macro, ou fazer definições globais com \xdef, ou preparar um registro de lista de tokens, ou usar vários tipos de TeXcondicionais.

A xintForconstrução do pacotexinttoolsé uma alternativa (verComo iterar em uma lista separada por vírgula?) que poupa o trabalho dessa codificação extra:

\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

O \xintifForFirst{YES}{N0}teste consiste em inserir uma tabulação &apenas na segunda e nas próximas células de uma determinada linha (aqui apenas uma linha). A \xintSeqmacro gera uma sequência aritmética de inteiros (por exemplo, {1}{2}{3}{4}). O \xintFor* #1 initera sobre seu argumento (seu primo sem estrela \xintForitera sobre uma lista separada por vírgula), deixando #1cada item um após o outro.

O mesmo código acima, mas usando um 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}

Aqui está agora um exemplo mais elaborado (pois usa dois loops aninhados) que constrói tabelas de multiplicação: \numexpré usado para a multiplicação do índice da linha pelo índice da coluna.

tabular dinâmico 2

Aqui está o 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 da definição de um LaTeXcomando do usuário, precisávamos dobrar o #para evitar confusão entre o ##1do loop e o #1sendo o primeiro parâmetro do comando.

Responder3

Se você não se importa em aprender um pouco de Python, o sagetexpacote pode lidar facilmente com tabelas dinâmicas; afinal Python é uma linguagem poderosa. A documentação do sagetex éaquie, em example.pdf, eles constroem o Triângulo de Pascal. Aqui está o código para algo mais próximo do que você pediu; a primeira linha é de 1 a 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}

insira a descrição da imagem aqui

Com a quantidade limitada de Python que você precisa aprender, imagino que provavelmente seja mais fácil do que programar em TeX. Você precisa saber: os loops for não incluem o último valor listado no intervalo e r é para string bruta e evita problemas que podem surgir por ter caracteres como barra invertida em sua string. Finalmente, %d serve para inserir números inteiros, %f para float e %s para string. O sagesilentambiente está compondo o código real que é inserido por meio de um arquivo sagestr.

Responder4

Isso pode ser feito de várias maneiras, conforme já sugerido pelos comentários e outras respostas. Aqui estão duas soluções usando pgffore pgfkeys.

Esta primeira solução funciona sem usar chaves:

\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 exemplo realiza a mesma tarefa usando chaves:

\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}

Em ambos os casos, as tabelas resultantes são:

insira a descrição da imagem aqui

informação relacionada