假设已使用 etoolbox 等定义了两个长度相同的列表。是否可以有一个函数\do
采用两个参数来同时处理两个列表,并从每个列表中采用一个参数?
例如,假设一个列表包含文本,第二个列表包含 URL,是否有可能有一个\do#1#2
函数\hyperref[#1]{#2}
同时返回两个列表?
我正在考虑 etoolbox dolistloop
,但有两个列表作为参数,而不仅仅是一个。
小型(必然不完整)的 MWE
\documentclass{article}
\usepackage{etoolbox}
\documentclass{article}
\usepackage{etoolbox}
\newcommand*\listone{}
\newcommand*\listtwo{}
\forcsvlist{\listadd\listone}{A,B,C}
\forcsvlist{\listadd\listtwo}{x,y,y}
\def\do#1#2{\hyperref[#1]{#2}}
% \dotwolistloop{\listone}{\listwo} This is the instruction I am looking for.
\end{document}
实际上,我需要能够同时处理三个列表,因此请提示解决方案,以便可以轻松扩展到两个以上的列表。
答案1
这将遍历三个列表,\testlist
在每个阶段执行三个参数命令。
\documentclass{article}
\def\listone{A,B,C}
\def\listtwo{x,y,z}
\def\listthree{1,2,3}
\newcommand\testlist[3]{[#1][#2][#3]\par}
\makeatletter
\def\loopthree#1#2#3{%
\edef\tmp{\noexpand\xthree
\unexpanded\expandafter{#1},\relax
\unexpanded\expandafter{#2},\relax
\unexpanded\expandafter{#3},\relax
}\tmp}
\def\xthree#1,#2\relax#3,#4\relax#5,#6\relax{%
\testlist{#1}{#3}{#5}%
\def\tmp{#2}%
\ifx\empty\tmp
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{\xthree#2\relax#4\relax#6\relax}}
\makeatother
\begin{document}
\loopthree\listone\listtwo\listthree
\end{document}
答案2
您可以使用expl3
和xparse
:
\documentclass{article}
\usepackage{xparse}
\usepackage{hyperref}
\ExplSyntaxOn
\NewDocumentCommand{\addtolist}{mm}
{% #1 = list name; #2 = items
\seq_clear_new:c { l_denis_list_#1_seq }
\clist_map_inline:nn { #2 }
{
\seq_put_right:cn { l_denis_list_#1_seq } { ##1 }
}
}
\NewDocumentCommand{\twolistloop}{mmm}
{% #1 = first list name; #2 = second list name; #3 = two argument macro
\seq_mapthread_function:ccN { l_denis_list_#1_seq } { l_denis_list_#2_seq } #3
}
\ExplSyntaxOff
\newcommand{\makehref}[2]{\href{#1}{#2}\par}
\addtolist{texts}{\TeX\ @ SX,Google,Yahoo}
\addtolist{urls}{
http://tex.stackexchange.com,
http://google.com,
http://yahoo.com
}
\begin{document}
\twolistloop{urls}{texts}{\makehref}
\end{document}
该宏\addtolist
将项目附加到序列,如果序列尚不存在,则创建该序列。该\twolistloop
宏使用两个序列,将每个序列中的一个项目传递给作为第三个参数给出的两个参数宏。
在我使用的示例中\href
,将其隐藏在另一个宏中,以便能够\par
在每次调用结束时添加。
每一行都是到相应站点的链接。
答案3
根据 David Carlisle 在上面提出的解决方案,我稍微更改了宏,以便它能够处理从 etoolbox 创建的列表。唯一的两个区别是 (1) etoolbox 列表以 catcode 3 | 字符分隔(而不是逗号)(2)列表已经以分隔符结尾(而上面的 David 在列表末尾手动添加了最后一个逗号)。所以整个代码是
\documentclass{article}
\usepackage{etoolbox}
% with etoolbox lists
\newcommand*\listone{}
\newcommand*\listtwo{}
\newcommand*\listthree{}
\forcsvlist{\listadd\listone}{A,B,C}
\forcsvlist{\listadd\listtwo}{x,y,y}
\forcsvlist{\listadd\listthree}{1,2,3}
\makeatletter
\catcode`\|=3
\def\loopthree#1#2#3{%
\edef\tmp{\noexpand\xthree
\unexpanded\expandafter{#1}\relax % no added delimiter here
\unexpanded\expandafter{#2}\relax % no added delimiter here
\unexpanded\expandafter{#3}\relax % no added delimiter here
} \tmp
}
\def\xthree#1|#2\relax#3|#4\relax#5|#6\relax{%
\dothree{#1}{#3}{#5}%
\def\tmp{#2}%
\ifx\empty\tmp
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{\xthree#2\relax#4\relax#6\relax}
}
\catcode`\|=12
\makeatother
\begin{document}
% as per David answer:
\newcommand\dothree[3]{[#1][#2][#3]\par}
\loopthree\listone\listtwo\listthree
% as a new example of the use of the dothree macro
Here is all three lists:
\renewcommand\dothree[3]{\item #1 + #2 + #3}
\begin{itemize}
\loopthree\listone\listtwo\listthree
\end{itemize}
\end{document}
非常感谢您的帮助。