如何用动态内容填充动态生成的表格?

如何用动态内容填充动态生成的表格?

如何在用动态数据填充表格的同时动态生成表格?

例如:假设我有

\def\N{10}

我想生成一个带有\N列的表格,其中每列的顶部单元格包含列号,例如

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

这是我得到最接近的答案:

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

但由于\expandafter,这给了我十列,每列包含 10。

有没有办法执行类似部分扩展的操作?我只想扩展,\arabic{i}但当然不是&

答案1

问题出在这一行:

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

\cols是一个令牌寄存器,因此\arabic{i}不会扩展。使用附加寄存器\expandafter并打印计数器值而不是\arabic有助于:

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

完整示例:

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

结果

可扩展版本

以下示例使用 e-TeX 的\numexpr。注意获取常量\if嵌套,并且&不能过早看到。

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

结果

答案2

Heiko 的回答解释了您的代码中的问题、如何解决它,以及如何使用可扩展整数循环以不同的方式进行(感谢\numexpr)。

A.Ellett 的回答提供了另外两种使用pgffor和的解决方案pgfkeys

DJP 的回答是一种使用外部工具的方法,这里通过Python code强大的功能来处理。Sagesagetex

这些答案都需要以某种形式进行一些额外的工作,例如(对于那些)在宏中TeX隐藏制表符,或使用进行全局定义,或准备标记列表寄存器,或使用各种条件。&\xdefTeX

xintFor包中的构造新工具是一种替代方案(参见如何迭代以逗号分隔的列表?),这样就省去了额外编码的麻烦:

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

动态表格

测试是仅在给定行(此处只有一行)的第二个和下一个单元格中 \xintifForFirst{YES}{N0}插入制表符。宏生成整数的算术序列(例如)。迭代其参数(其无星号表亲迭代逗号分隔的列表),让其每个项目一个接一个。&\xintSeq{1}{2}{3}{4}\xintFor* #1 in\xintFor#1

与上面相同的代码,但是使用计数器LaTeX

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

这里有一个更复杂的例子(因为它使用了两个嵌套循环),它构建了乘法表:\numexpr用于将行索引与列索引相乘。

动态表格 2

以下是代码:

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

正如我们\xintFor*在用户命令的定义中使用的那样LaTeX,我们需要将其加倍,#以避免##1循环的和#1命令的第一个参数之间的混淆。

答案3

如果您不介意学习一点 Python,该sagetex包可以轻松处理动态表;毕竟 Python 是一种强大的语言。sagetex 的文档是这里在 example.pdf 中,他们构造了帕斯卡三角形。以下是更接近您要求的代码;第一行是 1 到 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}

在此处输入图片描述

由于你需要学习的 Python 数量有限,我想它可能比用 TeX 编程更容易。你需要知道:for 循环不包括范围中列出的最后一个值,r 用于原始字符串,可避免字符串中出现反斜杠等字符可能引起的问题。最后,%d 用于插入整数,%f 用于浮点数,%s 用于字符串。环境sagesilent正在排版实际代码,然后通过 插入sagestr

答案4

正如评论和其他答案所建议的那样,可以通过多种方式实现这一点。以下是使用pgffor和 的两种解决方案pgfkeys

第一个解决方案无需使用密钥即可工作:

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

第二个示例使用键完成相同的任务:

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

无论哪种情况,结果表都是:

在此处输入图片描述

相关内容