列出各个群组

列出各个群组

我正在开发一个小宏,在其中我创建了一个\newcommand带有两个参数的宏。第二个参数只是一个名称。我想\newcommand多次使用它,最后我想要一个使用的所有第二个参数的完整列表。当我使用它一两次时,它会起作用,但当我使用它三次时会失败并报告超出 tex 容量。我能做些什么吗?这里有一个小例子,可以说明这个问题。

\documentclass{article}
\usepackage{tikz}
\usepackage{ifthen}

\newcommand{\List}{}
\newcommand{\names}[2]{%
\foreach \i in {#1} {%
    \i~belongs in #2.\par
    }
\let\OldList\List
\ifthenelse{\equal{\OldList}{}}{\renewcommand{\List}{#2}}{\renewcommand{\List}{\OldList ,#2}}
}

\begin{document}
\names{Paul,Peter,Hans}{group1}
\names{Erik,Robert}{group2}
%\names{Alex,Robin,Klaus}{group3}          %uncomment this line to produce error

The following groups participate: \List
\end{document}

答案1

我建议使用来自 的明确定义/测试过的宏etoolbox

可以\listgadd{\List}{}定义一个列表。

\forcsvlist{\listgadd{\List}}{#1}例如,可以用 添加逗号分隔的值列表。

使用宏\shownames[2]可以循环遍历列表,当前列表条目包含在最后的宏的参数通过

\forlistloop{\shownames{#1}}{\List}

\documentclass{article}
\usepackage{etoolbox}%

\listgadd{\List}{} % Dummy list
\listgadd{\GroupList}{} % Dummy list


\newcommand{\shownames}[2]{%
#2 belongs in #1\par
}%

\newcommand{\showallnames}[1]{%
  #1\par
}%

\newcommand{\List}{}
\newcommand{\names}[2]{%
  \forcsvlist{\listgadd{\List}}{#1}%
  \forcsvlist{\listgadd{\GroupList}}{#2}%
  \forlistloop{\shownames{#2}}{\List}%
}%


\begin{document}
\names{Paul,Peter,Hans}{group1}
\names{Erik,Robert}{group2}
\names{Alex,Robin,Klaus}{group3}          

The following groups participate:

\forlistloop{\showallnames}{\GroupList}%
\end{document}

在此处输入图片描述

答案2

让我们看看会发生什么。使用第一个\names{Paul,Peter,Hans}{group1}命令,您重新定义\List为包含group1。使用第二个命令\names{Erik,Robert}{group2}\List不再为空,因此您将其定义为

\OldList,group2

其中\OldList扩展为group1

现在问题出现了:当你执行第三个命令时\let\OldList\List,所以\OldList会扩展为\OldList,group2并且,当

\ifthenelse{\equal{\OldList}{}

执行后,LaTeX 会“一直”扩展:因此它会扩展 ,\OldList,group2扩展为\OldList,group2,group2,扩展为 ... 答对了!无限循环。您基本上不是想用另一瓶酒来装满一瓶,而是用另一瓶酒本身!

一个更好的方法是改为扩展\List:不\let\OldList\List,而只是

\ifthenelse{\equal{\List}{}}
  {\renewcommand{\List}{#2}}
  {\expandafter\renewcommand\expandafter\List\expandafter{\List,#2}}

答案3

\OldList如果您将其定义为内容\List而不是尝试使其成为相同的宏,它就会起作用。(注意:其他人将能够更好地解释这一点!)

\documentclass{article}
\usepackage{ifthen,pgffor}

\newcommand{\List}{}
\newcommand{\names}[2]{%

\foreach \i in {#1} {%
    \i~belongs in #2.\par
    }
\ifthenelse{\equal{\List}{}}{\renewcommand{\List}{#2}}{\expandafter\renewcommand\expandafter\List\expandafter{\List, #2}}% safer (see comments) though I don't actually understand why
}

\begin{document}
\names{Paul,P\'eter,Hans}{group1}
\names{Erik,Robert}{group2}
\names{Alex,Robin,Klaus}{group3}

The following groups participate: \List

\end{document}

我删除它tikz只是因为它与你的 MWE 基本无关,而且是一个不需要加载的大包!但正如 cgnieder 指出的那样,你确实需要它,pgffor所以我用它代替了它。

小组演示

答案4

这是expl3您的代码版本。\List宏会从组列表中删除所有重复项,这样您就可以执行\names{...}{groupX}两次,而无需groupX在输出中出现两次。

\documentclass{article}
\pagestyle{empty}
\usepackage{xparse}
\ExplSyntaxOn

\seq_new:N \l_gilean_groups_seq

\NewDocumentCommand \names { m m }
 {
  \gilean_names:nn { #1 } { #2 }
 }

\NewDocumentCommand \List { }
 {
  \par
  \seq_remove_duplicates:N \l_gilean_groups_seq
  \seq_use:Nn \l_gilean_groups_seq { \par }
 }

\cs_new_protected:Npn \gilean_names:nn #1#2
 {
  \clist_map_inline:nn { #1 }
   {
    ##1 ~ belongs ~ in ~ #2 \par
   }
   \seq_put_right:Nn \l_gilean_groups_seq { #2 }
 }

\ExplSyntaxOff
\begin{document}
\names{Paul,Peter,Hans}{group1}
\names{Erik,Robert}{group2}
\names{Alex,Robin,Klaus}{group3}
\names{Max,Donald,Robert}{group1}
The following groups participate: \List
\end{document}

在此处输入图片描述

列出各个群组

我们现在有了\listgroups[<separator>]列出所有组并将分隔符作为可选参数的。此外,还有\listnames[<separator>]{<group>}列出所有成员的<group>

\documentclass{article}
\pagestyle{empty}
\usepackage{xparse}
\ExplSyntaxOn

\seq_new:N \l_gilean_names_seq
\seq_new:N \l_gilean_groups_seq

\NewDocumentCommand \names { m m }
 {
  \gilean_names:nn { #1 } { #2 }
 }

\NewDocumentCommand \listnames { O{\par} m }
 {
  \int_zero:N \l_tmpa_int
  \seq_clear:N \l_tmpa_seq
  \seq_map_inline:Nn \l_gilean_names_seq
   {
    \int_incr:N \l_tmpa_int
    \str_if_eq_x:nnT { #2 } { \seq_item:Nn \l_gilean_groups_seq { \l_tmpa_int } }
     { \seq_put_right:Nn \l_tmpa_seq { ##1 } }
   }
   \seq_use:Nn \l_tmpa_seq { #1 }
 }

\NewDocumentCommand \listgroups { O{\par} }
 {
  \group_begin:
  \seq_remove_duplicates:N \l_gilean_groups_seq
  \seq_use:Nn \l_gilean_groups_seq { #1 }
  \group_end:
 }

\cs_new_protected:Npn \gilean_names:nn #1#2
 {
  \clist_map_inline:nn { #1 }
   {
    \seq_put_right:Nn \l_gilean_names_seq  { ##1 }
    \seq_put_right:Nn \l_gilean_groups_seq {  #2 }
   }
 }

\ExplSyntaxOff
\begin{document}
\names{Paul,Peter,Hans}{group1}
\names{Erik,Robert}{group2}
\names{Alex,Robin,Klaus}{group3}
\names{Max,Donald,Robert}{group1}
The following groups exist:\par
\listgroups[, ]

These people are in group1:\par
\listnames[, ]{group1}

These people are in group2:\par
\listnames[, ]{group2}
\end{document}

在此处输入图片描述

相关内容