我想创建一个表格,显示某些给定输入列表的公式的评估结果。
我最初的想法是使用FP循环内的包\@for
。然而,这在表格环境中不起作用。
我当前的解决方法是使用tabto
格式化,但当我想添加更长的数字,有漂亮的垂直或水平线,或者只是将整个东西居中时,这显然不是一种可持续的方式。
使用解决方法的最小工作示例:
\documentclass{article}
\usepackage{tabto} % just for the workaround
\usepackage{fp}
\begin{document}
\noindent
$a$ \tabto{1cm} $b$ \tabto{2cm} $a+b$\\ % table header
\makeatletter
\FPset{a}{1}
\@for \b:={1, 1.5, 2, 42}\do{
\FPeval{\result}{round(a+b:2)}
\a \tabto{1cm} \b \tabto{2cm} \result \\ % table row
}
\makeatother
\end{document}
- 请注意,我不是在寻找
1..N
循环,而是在寻找迭代给定浮点值列表的循环。 - fp 不是一个硬性要求,如果它妨碍了你,就建议采用替代方案。
- 我希望有一个可以使用 pdflatex 的解决方案,而不是基于 Lua 的解决方案。
问题:我如何生成像这样的实际表格?
答案1
也许通过使用pgfplotstable
包
\documentclass{article}
\usepackage{pgfplotstable}
\usepackage{booktabs}
\pgfplotsset{compat=1.18}
\pgfplotstableset{
create on use/a/.style={create col/set={1}}, % define the a column
create on use/b/.style={create col/set list={1, 1.5, 2, 42}}, % define the b column
create on use/tempresult/.style={
create col/expr={(\thisrow{a}+\thisrow{b})/2}}, % result=(a+b)/2 % define the result column for the temporary table
%
create on use/result/.style={
create col/copy column from table={\temptable}{tempresult}} % define the result column as a copy of the tempresult from \temptable
}
% create two new tables \temptable and \mytable
\pgfplotstablenew[columns={a,b,tempresult}]{4}\temptable % 4 rows
\pgfplotstablenew[columns={result}]{4}\mytable
\begin{document}
\section {all columns} %
%
% typeset the temporary table if needed
\pgfplotstabletypeset[every last row/.style={after row=\bottomrule},
every head row/.style={before row=\toprule,after row=\midrule},
columns/temp/.style={column name={result}}]\temptable
\section{Only the result column}
%
% typeset the final table
\pgfplotstabletypeset[every last row/.style={after row=\bottomrule},
every head row/.style={before row=\toprule,after row=\midrule},]\mytable
\end{document}
答案2
这是针对任何(最多 9 个)变量的相当通用的方法。
\documentclass{article}
\usepackage{booktabs}
\ExplSyntaxOn
\NewDocumentCommand{\tableofvalues}{mmmm}
{% #1 = list of variables
% #2 = formula to compute in terms of the variables
% #3 = formula in xfp terms
% #4 = set of comma list separated values for the variables
\seriously_tov_main:nnnn { #1 } { #2 } { #3 } { #4 }
}
% example call
% \tableofvalues{a,b}{a+b}{round(#1+#2,2)}{
% {1, 2.3, 4, -2}
% {1, 1.5, 2, 42}
% }
\tl_new:N \l__seriously_tov_body_tl
\tl_new:N \l__seriously_tov_sgn_tl
\seq_new:N \l__seriously_tov_rows_seq
\seq_new:N \l__seriously_tov_args_seq
\clist_new:c { l__seriously_tov_1_clist }
\clist_new:c { l__seriously_tov_2_clist }
\clist_new:c { l__seriously_tov_3_clist }
\clist_new:c { l__seriously_tov_4_clist }
\clist_new:c { l__seriously_tov_5_clist }
\clist_new:c { l__seriously_tov_6_clist }
\clist_new:c { l__seriously_tov_7_clist }
\clist_new:c { l__seriously_tov_8_clist }
\clist_new:c { l__seriously_tov_9_clist }
\cs_new_protected:Nn \seriously_tov_main:nnnn
{
% compute the number of arguments
\tl_set:Nx \l__seriously_tov_sgn_tl
{
\prg_replicate:nn { \clist_count:n { #1 } } { n }
}
% make a temporary function to do the computation
\cs_set:cn { __seriously_tov_compute:\l__seriously_tov_sgn_tl } { \fp_eval:n { #3 } }
% this is a mouthful, so we define a shorthand
\cs_set_eq:Nc \__seriously_tov_compute:w { __seriously_tov_compute:\l__seriously_tov_sgn_tl }
% we want to absorb the values traversing the lists
\int_step_inline:nn { \clist_count:n { #1 } }
{
\clist_set:cx { l__seriously_tov_##1_clist } { \tl_item:nn { #4 } { ##1 } }
}
\seq_clear:N \l__seriously_tov_rows_seq
\seq_clear:N \l__seriously_tov_args_seq
\int_step_inline:nn { \clist_count:c { l__seriously_tov_1_clist } }
{
\tl_clear:N \l_tmpa_tl \tl_clear:N \l_tmpb_tl
\int_step_inline:nn { \clist_count:n { #1 } }
{
\tl_put_right:Nx \l_tmpa_tl { \clist_item:cn { l__seriously_tov_####1_clist } { ##1 } & }
\tl_put_right:Nx \l_tmpb_tl { { \clist_item:cn { l__seriously_tov_####1_clist } { ##1 } } }
}
\tl_put_left:Nn \l_tmpb_tl { \__seriously_tov_compute:w }
\tl_put_right:Nn \l_tmpb_tl { \\ }
\seq_put_right:NV \l__seriously_tov_rows_seq \l_tmpa_tl
\seq_put_right:NV \l__seriously_tov_args_seq \l_tmpb_tl
}
% now we can build the table body
\tl_set:Nx \l__seriously_tov_body_tl
{
\seq_mapthread_function:NNN \l__seriously_tov_rows_seq \l__seriously_tov_args_seq \use:nn
}
% and we output the table
$\begin{array}{ *{\clist_count:n { #1 }}{c}c }
\toprule
\clist_use:nn { #1 } { & } & #2 \\
\midrule
\tl_use:N \l__seriously_tov_body_tl
\bottomrule
\end{array}$
}
\ExplSyntaxOff
\begin{document}
\tableofvalues{a,b}{a+b}{round(#1+#2,2)}{
{1, 2.3, 4, -2}
{1, 1.5, 2, 42}
}
\bigskip
\tableofvalues{x,y,z}{xyz}{#1*#2*#3}{
{0.3,23,92}
{1,2,3}
{100,200,-100}
}
\end{document}
这段代码背后的想法是什么?声明了一定数量的变量,我们可以通过 来访问它们的数量\clist_count:n{#1}
。
下一个任务是定义一个函数来计算值,并且需要接受与变量数量相同的参数。因此,我们可以利用expl3
函数签名来提供所需数量的参数;在第一个使用示例中,我们将得到
\cs_set:cn { __seriously_tov_compute:nn } { \fp_eval:n { #3 } }
因为我们已经nn
通过生成了\prg_replicate:nn
。
但是,在下面的代码中使用它太冗长了,所以我用签名定义了一个别名:w
。替换文本是通过以适合此类表达式的语法应用于\fp_eval:n
包含公式的参数来定义的。#3
下一个任务是生成要传递给 的参数列表\__seriously_tov_compute:w
。 的最后一个参数\tableofvalues
应包含与变量一样多的括号列表,并且这些列表应具有相同数量的项目。
这些列表首先使用循环将变量数量存储在clist
变量中。接下来,我们同时遍历这些列表,从每个列表中提取具有相同位置的项目,然后构建两个序列。在使用示例中,第一个序列将包含项目(括号仅用于分隔它们)
{1 & 1 &}
{2.3 & 1.5 &}
{4 & 2 &}
{-2 & 42 &}
第二个序列将包含
{\__seriously_tov_compute:w {1}{1} \\}
{\__seriously_tov_compute:w {2.3}{1.5} \\}
{\__seriously_tov_compute:w {4}{2} \\}
{\__seriously_tov_compute:w {-2}{42} \\}
(事实并非如此:序列实际上将包含计算值)。
最后,我们通过使用简单地逐个传递其参数的\seq_mapthread_function:NNN
函数按顺序从每个序列中获取项目来构建表体。\use:nn
一旦表体准备好,就可以使用合适的前导码输出表格。