如何将 do 函数应用于两个列表?

如何将 do 函数应用于两个列表?

假设已使用 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

您可以使用expl3xparse

\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}

非常感谢您的帮助。

相关内容