在多行命令中使用计数器

在多行命令中使用计数器

我想创建一个宏,从列表创建一个表,并将第一列合并。我仍然有两个问题,第一个是获取列表的大小,目前我得到的是 size + 1 ;(,第二个是将结果用于 \multirow 的第一个参数。我考虑过类似 \multirow{\sizeList}{*}{some data} 的东西...但它不起作用。


\documentclass{article}
\usepackage{float}
\usepackage{etoolbox}
\usepackage{multirow}

\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand \countItems {m}{\clist_count:N #1}
\newcommand\mylist{} 
\newcommand{\addRow}[2]{
\def\delim{&}
    \listadd{\mylist}{ \delim#1,#2}
}
\newcommand{\makerow}[1]{%
\def\delim{ & }%
\renewcommand*{\do}[1]{##1 \delim}%
\docsvlist{#1}%
}
\newcommand{\dorow}[1]{\makerow{#1} \\ \cline{2-3}}
\newcommand{\makeTable}{
    \begin{table}[H]
        \begin{tabular}{|c|c|c|}
            \hline
            Uppercase & Number & Lowercase \\ \hline
            \multirow{4}{*}{some item} \forlistloop{\dorow}{\mylist} %\multirow{\countItems{\mylist}-1{*}{some item}
            \hline
        \end{tabular}
    \end{table}
}
\ExplSyntaxOff

\begin{document} 
    \addRow{A}{1}
    \addRow{B}{2}
    \addRow{C}{3}
    \addRow{D}{4}
    
    \makeTable  
    This list has \countItems{\mylist} elements. %>>>> does not get the right length 

\end{document}

结果: 在此处输入图片描述

答案1

我添加了\show\mylist您的代码。(就在说明有多少个项目的语句之前。)这在我的终端上显示以下内容:

> \mylist=macro:
->\delim A,1|\delim B,2|\delim C,3|\delim D,4|

您可以看到,此列表中确实有 5 个项目。有 4 个逗号和 5 个项目,因为每个逗号都\addRow添加了<content before>,<content after>。因此,添加第一个项目后,列表包含 2 个,添加第二个项目后,列表包含 3 个,依此类推。

您还使用了 LaTeX 2e 和 TeX 的混合版本。虽然现在expl3很难(不可能?)完全使用,但这可能会更简洁一些。expl3

对于计数,在我看来,你至少有两个选择。你可以直接扣除 1,因为你的代码在设计上添加了 n+1 个项目。或者,你可以保留一个单独的计数。或者你可以重组事物。哪一个最合理可能取决于你的上下文的进一步特征。

接下来我采用重构路线。我将给出的两个参数存储\addRow在两个序列中,然后简单地将它们两两地输入到函数中以创建行。然后任一序列的计数都会给出行数。我们可以\mutlirow通过使用expl3函数变体将其直接输入,以便在函数看到它之前完成计数。

由于带有垂直线和较小间距的表格通常被认为是次优的,因此我还提供了一个booktabs版本。此版本不使用,H因为H这不是个好主意。最好避免使用非浮动浮动。相反,我使用从包中center提供一些间距和,因为对标题的需求通常会激发人们对非浮动浮动的渴望。\captionofcaption

两个比较表

\documentclass{article}
\usepackage{float}
\usepackage{multirow}
\usepackage{booktabs}
\usepackage{caption}

% not needed with recent LaTeX kernels
% uncomment one or both if you have an older install
% \usepackage{expl3}
% \usepackage{xparse}

\ExplSyntaxOn
% use two sequences and forget storing commas
\seq_new:N \l_francoisfem_itemsa_seq
\seq_new:N \l_francoisfem_itemsb_seq
\NewDocumentCommand \countItems {m}
{
  \seq_count:c { l_francoisfem_#1_seq }
}
\NewDocumentCommand {\addRow} {mm}{ % just store the arguments pairwise 
  \seq_put_right:Nn \l_francoisfem_itemsa_seq { #1 }
  \seq_put_right:Nn \l_francoisfem_itemsb_seq { #2 }
}
\cs_new_protected_nopar:Nn \francoisfem_make_row:nn
{ % we add the alignment and row endings etc. here
  & #1 & #2 \\ \cline{2-3}
}
\cs_new_protected_nopar:Nn \francoisfem_makenicer_row:nn
{ % for booktabs version
  & #1 & #2 \\ 
}
\cs_new_protected_nopar:Nn \francoisfem_multirow:nnn
{ % make expansion easy for multirow 
  \multirow {#1} {#2} {#3}
}
% generate a version of multirow which expands its first argument once, so we get the result of the count
\cs_generate_variant:Nn \francoisfem_multirow:nnn { onn }
\NewDocumentCommand{\makeTable}{ O {*} D () { some ~ item } }
{ % two optional arguments: square brackets (defaults to *); parentheses (defaults to 'some item'')
  \begin{table}[H] % note that H is Really Not A Good Idea
    \centering
    \caption{Usually ~ why ~ people ~ want ~ non-floating ~ floats}
    \begin{tabular}{|c|c|c|} % note that vertical rules and standard spacing don't make for professional-looking results (see e.g. booktabs)
      \hline
      Uppercase & Number & Lowercase \\ \hline
      \francoisfem_multirow:onn % the o means the first argument gets expanded *before* multirow sees it
      {
        \seq_count:N \l_francoisfem_itemsa_seq 
      }{#1}{#2}   
      % Noah's ark : we feed the contents of the sequences in two-by-two to our row-maker function
      \seq_map_pairwise_function:NNN \l_francoisfem_itemsa_seq \l_francoisfem_itemsb_seq \francoisfem_make_row:nn
      \hline
    \end{tabular}
  \end{table}
}
\NewDocumentCommand \makenicerTable { O {*} D () { some ~ item } }
{ % booktabs version
  \begin{center} % don't use a float if we don't want it to move
    \captionof{table}{If ~ we ~ want ~ a ~ caption}
    \begin{tabular}{ccc} % no vertical rules 
      \toprule
      Uppercase & Number & Lowercase \\ \midrule
      \francoisfem_multirow:onn 
      {
        \seq_count:N \l_francoisfem_itemsa_seq 
      }{#1}{#2}   
      \seq_map_pairwise_function:NNN \l_francoisfem_itemsa_seq \l_francoisfem_itemsb_seq \francoisfem_makenicer_row:nn
      \bottomrule
    \end{tabular}
  \end{center}
}
\ExplSyntaxOff

\begin{document} 
\addRow{A}{1}
\addRow{B}{2}
\addRow{C}{3}
\addRow{D}{4}

\makeTable  

This list has \countItems {itemsa} elements. 


\makenicerTable
\end{document}

答案2

睡了一晚后,可能的解决方案是:):

\documentclass{article}
\usepackage{float}
\usepackage{etoolbox}
\usepackage{multirow}

\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand \countItems {m}{\clist_count:N #1}
\newcommand\mylist{} 
\newcounter{lenList} %<<<<<< creating a counter
\newcommand{\addRow}[2]{
    \addtocounter{lenList}{1} %<<<<<< when add a row add 1 to the counter
    \def\delim{&}
    \listadd{\mylist}{ \delim#1,#2}
}
\newcommand{\makerow}[1]{%
    \def\delim{ & }%
    \renewcommand*{\do}[1]{##1 \delim}%
    \docsvlist{#1}%
}
\newcommand{\dorow}[1]{\makerow{#1} \\ \cline{2-3}}
\newcommand{\makeTable}{
    \begin{table}[H]
        \begin{tabular}{|c|c|c|}
            \hline
            Uppercase & Number & Lowercase \\ \hline 
            \multirow{\thelenList}{*}{some item} \forlistloop{\dorow}{\mylist} %<<<< using the counter ... 
            \hline
        \end{tabular}
    \end{table}
}
\ExplSyntaxOff

\begin{document} 
    \addRow{A}{1}
    \addRow{B}{2}
    \addRow{C}{3}
    \addRow{D}{4}
    
    \makeTable  
    This list has \countItems{\mylist} elements.

\end{document}

答案3

不要混淆expl3etoolbox你只需要设置您可以协调使用的数据集。

如果您需要两列以上的数据,则会稍微复杂一些。

\documentclass{article}

\usepackage{etoolbox}
\usepackage{multirow}

\ExplSyntaxOn

\seq_new:N \l__francois_table_a_seq
\seq_new:N \l__francois_table_b_seq
\tl_new:N \l__francois_table_alast_tl
\tl_new:N \l__francois_table_blast_tl

\NewDocumentCommand{\clearRows}{}
 {
  \seq_clear:N \l__francois_table_a_seq
  \seq_clear:N \l__francois_table_b_seq
 }

\NewDocumentCommand{\addRow}{mm}
 {
  \seq_put_right:Nn \l__francois_table_a_seq { #1 }
  \seq_put_right:Nn \l__francois_table_b_seq { #2 }
 }

\NewDocumentCommand{\makeTable}{}
 {
  % last row is special
  \seq_pop_right:NN \l__francois_table_a_seq \l__francois_table_alast_tl
  \seq_pop_right:NN \l__francois_table_b_seq \l__francois_table_blast_tl
  % make the tabular
  \begin{tabular}{|c|c|c|}
  \hline
  % headers
  Uppercase & Number & Lowercase \\ \hline
  % start with \multirow
  \multirow{\int_eval:n { \seq_count:N \l__francois_table_a_seq + 1 }}{*}{some~item}
  \seq_map_pairwise_function:NNN
   \l__francois_table_a_seq % first sequence
   \l__francois_table_b_seq % second sequence
   \__francois_table_make:nn % what to do
  % last row, no \cline
  & \l__francois_table_alast_tl & \l__francois_table_blast_tl \\
  \hline
  \end{tabular}
 }

\cs_new_protected:Nn \__francois_table_make:nn
 {
  & #1 & #2 \\ \cline{2-3}
 }

\ExplSyntaxOff

\begin{document} 

\clearRows
\addRow{A}{1}
\addRow{B}{2}
\addRow{C}{3}
\addRow{D}{4}

\begin{table}[htp]
\centering

\makeTable  

\caption{A table with some data}

\end{table}

\end{document}
  1. 切勿使用[H]

  2. 如果不需要标题,那么使用table环境就没有意义了。

  3. 仔细看看结果:你真的认为这\multirow有帮助吗?“某些项目”部分实际上不是表格的一部分,对吗?

  4. 垂直规则也无济于事。

在此处输入图片描述

相关内容