当创建元组的语法是预定义的并且无法更改时,模拟“元组”数据结构

当创建元组的语法是预定义的并且无法更改时,模拟“元组”数据结构

假设我有一个接受三个参数的宏\createcontact。现在,我不想在扩展期间使用这些参数,而是想将它们单独保存以供以后使用和检索。上述宏在以下上下文中使用:

\newcommand{\myfirstauthor}{\createcontact{Alice}{Munich}{Germany}}
\newcommand{\mysecondauthor}{\createcontact{Bob}{London}{United Kingdom}}
% and so forth

我该如何实现\createcontact才能从 等中提取传递给它的各个参数\myfirstauthor\mysecondauthor提取的代码会是什么样子?换句话说,我需要如何定义\createcontact一个宏,\extractsecond以便\extractsecond\myfirstauthor将其扩展为Munich

编辑:请注意,只有 的定义\createcontact可以调整,而 等的定义则不能调整\myfirstauthor\mysecondauthor也就是说,上述使用模式必须保持“原样”。

进行此练习的原因是上述模式在用户文档中随处可见。我想对参数进行更复杂的处理,\createcontact而不是简单地使用它们一次在宏中。(例如,我想Munich在一个上下文中使用,Germany在另一个上下文中使用。)

根据 Peter 的要求,这里有一个“可编译”的示例,其中有占位符而不是我感兴趣的命令:

\documentclass{article}

% HOW TO IMPLEMENT THIS?
\newcommand{\createcontact}[3]{...}
\newcommand{\extractfirst}[1]{...}
\newcommand{\extractsecond}[1]{...}
\newcommand{\extractthird}[1]{...}
% HOW TO IMPLEMENT THIS?

% DO NOT CHANGE OR MOVE THIS
\newcommand{\myfirstauthor}{\createcontact{Alice}{Munich}{Germany}}
\newcommand{\mysecondauthor}{\createcontact{Bob}{London}{United Kingdom}}
% DO NOT CHANGE OR MOVE THIS

\begin{document}
  \extractfirst{\myfirstauthor} lives in \extractsecond{\myfirstauthor}
  which is located in \extractthird{\myfirstauthor};
  this may or may not be true for \extractfirst{\mysecondauthor}.
\end{document}

答案1

使用 lambda 列表:

\documentclass{minimal}
\usepackage{lambda} % http://www.ctan.org/pkg/lambda-lists
%
\def\createcontact#1#2#3{\Listize[#1,#2,#3]}
\let\extractfirst\Head
\def\extractsecond#1{\extractfirst{\Tail{#1}}}
\def\extractthird#1{\extractsecond{\Tail{#1}}}
%
\newcommand{\myfirstauthor}{\createcontact{Alice}{Munich}{Germany}}
\newcommand{\mysecondauthor}{\createcontact{Bob}{London}{United Kingdom}}
%
\begin{document}
  \extractfirst{\myfirstauthor} lives in \extractsecond{\myfirstauthor}
  which is located in \extractthird{\myfirstauthor};
  (or \Head{\Tail{\Tail{\myfirstauthor}}},
  or \Head{\Reverse{\myfirstauthor}})
  this may or may not be true for \extractfirst{\mysecondauthor}.
\end{document}

答案2

基本解决方案:

如果没有更多细节,很难知道像这样简单的事情是否适合您:您调用\myfirstauthor{Kenobi}{General}{1138},然后要访问每个成员,您只需引用\myfirstauthorName\myfirstauthorRank\myfirstauthorSerialNum

在此处输入图片描述

\documentclass{article}

\newcommand{\myfirstauthor}[3]{%
    \newcommand{\myfirstauthorName}{#1}%
    \newcommand{\myfirstauthorRank}{#2}%
    \newcommand{\myfirstauthorSerialNum}{#3}%
}

\begin{document}
\myfirstauthor{Kenobi}{General}{1138}

The details of the first author are:

\medskip
\begin{tabular}{rl}
Name: & \myfirstauthorName\\
Rank: & \myfirstauthorRank\\
Serial Number: & \myfirstauthorSerialNum
\end{tabular}
\end{document}

替代解决方案:

您可以指定宏的第一个参数来区分它们,而不是创建单独的宏列表,等等\myfirstauthor。这样可以得到更灵活的解决方案,因为您可以动态创建宏。因此,使用此解决方案,您可以使用(或省略,因为这是默认值),但其他宏可以简单地通过定义,并像上面的例子一样访问,以得出:\mysecondauthor\myauthor\myauthor[first]{Kenobi}{General}{1138}first\myauthor[second]{Dooku}{Count}{66}

在此处输入图片描述

要创建另一个,您只需使用\myauthor[third]{}{}{},等等......

\documentclass{article}

\newcommand{\myauthor}[4][first]{%
    \expandafter\newcommand\csname my#1authorName\endcsname{#2}%
    \expandafter\newcommand\csname my#1authorRank\endcsname{#3}%
    \expandafter\newcommand\csname my#1authorSerialNum\endcsname{#4}%
}

\begin{document}
\myauthor{Kenobi}{General}{1138}
\myauthor[second]{Dooku}{Count}{66}

The details of the first two authors are:

\medskip
\begin{tabular}{rll}
Name: & \myfirstauthorName & \mysecondauthorName\\
Rank: & \myfirstauthorRank & \mysecondauthorRank\\
Serial Number: & \myfirstauthorSerialNum & \mysecondauthorSerialNum
\end{tabular}
\end{document}

根据给定的 MWE 解决方案:

通过修改限制,您可以使用基于 if或\AtBeginDocument的定义来更改调用 :\createcontact\myfirstauthor\mysecondauthor

在此处输入图片描述

\documentclass{article}

% HOW TO IMPLEMENT THIS?
\newcommand{\createcontact}[3]{}
\newcommand{\extractfirst}[1]{\csname #1Name\endcsname}
\newcommand{\extractsecond}[1]{\csname #1City\endcsname}
\newcommand{\extractthird}[1]{\csname #1Country\endcsname}

\newcommand{\myfirstauthorName}{}%
\newcommand{\myfirstauthorCity}{}%
\newcommand{\myfirstauthorCountry}{}%
\newcommand{\CreateFirstContact}[3]{%
    \renewcommand{\myfirstauthorName}{#1}%
    \renewcommand{\myfirstauthorCity}{#2}%
    \renewcommand{\myfirstauthorCountry}{#3}%
}
\newcommand{\mysecondauthorName}{}%
\newcommand{\mysecondauthorCity}{}%
\newcommand{\mysecondauthorCountry}{}%
\newcommand{\CreateSecondContact}[3]{%
    \renewcommand{\mysecondauthorName}{#1}%
    \renewcommand{\mysecondauthorCity}{#2}%
    \renewcommand{\mysecondauthorCountry}{#3}%
}


\AtBeginDocument{%
    \let\OldFirstAuthor\myfirstauthor
    \let\OldSecondAuthor\mysecondauthor
    \renewcommand{\myfirstauthor}{\let\createcontact\CreateFirstContact\OldFirstAuthor}
    \renewcommand{\mysecondauthor}{\let\createcontact\CreateSecondContact\OldSecondAuthor}
    \myfirstauthor
    \mysecondauthor
}
% HOW TO IMPLEMENT THIS?

% DO NOT CHANGE THIS
\newcommand{\myfirstauthor}{\createcontact{Alice}{Munich}{Germany}}
\newcommand{\mysecondauthor}{\createcontact{Bob}{London}{United Kingdom}}

\begin{document}
\noindent
  \extractfirst{myfirstauthor} lives in \extractsecond{myfirstauthor}
  which is located in \extractthird{myfirstauthor};
  this may or may not be true for \extractfirst{mysecondauthor}.
\end{document}

答案3

感谢 Bruno Le Floch 提出这个想法,以下是我认为“对我有用”的做法:

\documentclass{standalone}
% ONE POSSIBLE SOLUTION
\newcommand{\createcontact}[3]{}
\newcommand{\extractfirst}[1]{\renewcommand{\createcontact}[3]{##1}#1}
\newcommand{\extractsecond}[1]{\renewcommand{\createcontact}[3]{##2}#1}
\newcommand{\extractthird}[1]{\renewcommand{\createcontact}[3]{##3}#1}
% ONE POSSIBLE SOLUTION

% DO NOT CHANGE THIS
\newcommand{\myfirstauthor}{\createcontact{Alice}{Munich}{Germany}}
\newcommand{\mysecondauthor}{\createcontact{Bob}{London}{United Kingdom}}
% DO NOT CHANGE THIS
\begin{document}

  \extractfirst{\myfirstauthor} lives in \extractsecond{\myfirstauthor}
  which is located in \extractthird{\myfirstauthor};
  this may or may not true for \extractfirst{\mysecondauthor}.
\end{document}

编译结果

相关内容