通过循环列表生成表

通过循环列表生成表

我想创建一个表格,显示某些给定输入列表的公式的评估结果。

我最初的想法是使用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

一旦表体准备好,就可以使用合适的前导码输出表格。

相关内容