
如何動態生成表格並用動態資料填充表格?
例:假設我有
\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
海子的回答解釋了您的程式碼存在的問題、如何解決該問題,以及如何使用可擴展整數循環以不同的方式進行操作(感謝\numexpr
)。
A.埃萊特的回答pgffor
使用和提供了另外兩個解決方案pgfkeys
。
DJP的回答是一種使用外部工具的方法,這裡由強大的viaPython code
處理。Sage
sagetex
這些答案都需要以一種或另一種形式進行一些額外的工作,例如(對於那些TeX
)將表格隱藏&
在巨集中,或使用 進行全域定義\xdef
,或準備令牌清單暫存器,或使用各種TeX
條件。
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
用於行索引與列索引的乘法。
這是代碼:
\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}
無論哪種情況,結果表都是: