我正在尝试etoolbox
通过创建自己的自定义宏\listfront
和来使用该包创建一个简单的队列\listfrontpop
。这是我第一次将 TeX 代码使用到这种程度,所以我的理解充其量只是浅薄的。以下是我目前所拥有的:
\documentclass{minimal}
\usepackage{etoolbox}
\newcommand{\listfront}[1]{%
\renewcommand{\do}[1]{##1\listbreak}%
\dolistloop{#1}%
}
\newcommand{\listpopfront}[1]{%
\def\templistfront{\listfront{#1}}%
\listgremove{#1}{\templistfront}%
}
\begin{document}
\newcommand{\mylist}{}%
\listgadd{\mylist}{potty}%
\listgadd{\mylist}{sam}%
\listfront{\mylist}% potty <- as expected
\listpopfront{\mylist}% potty should be removed
\listfront{\mylist}% potty <- expected sam!
\end{document}
我期望得到pottysam
,但得到的pottypotty
却是 。我怀疑问题在于
...
\begin{document}
...
\listpopfront{\mylist}%
...
\end{document}
因为如果我将其替换为\listgremove{\mylist}{potty}
,我会得到pottysam
。但是,如果我执行类似操作\def\potty{potty}
,然后执行\listgremove{\mylist}{\potty}
,我会pottypotty
再次得到。
我该怎么去\listpopfront
上班?出了什么问题?
到目前为止,我的解决方案是\listpopfront
定义为
\newcommand{\listpopfront}[1]{%
\renewcommand{\do}[1]{%
\listgremove{#1}{##1}\listbreak%
}%
\dolistloop{#1}%
}
这解决了我的问题,但是却非常不优雅。
答案1
这是一个解决方案,它只使用 etoolbox 的文档,而不使用其内部组件,并且是从您的 MWE 开发而来的。我允许自己使用它,\def
因为您已经使用过它了。
\documentclass{article}
\usepackage{etoolbox}
\newcommand{\listfront}[1]{%
\renewcommand{\do}[1]{##1\listbreak}%
\dolistloop{#1}%
}
\newcommand{\listpopfront}[1]{%
\begingroup
\long\def\do##1{\long\def\templistfront{##1}\listbreak}%
\dolistloop{#1}%
\def\x{\endgroup\listgremove{#1}}%
\expandafter\x\expandafter{\templistfront}%
}
\begin{document}
\newcommand{\mylist}{}%
\listgadd{\mylist}{potty}%
\listgadd{\mylist}{sam}%
\listfront{\mylist}% potty <- as expected
\listpopfront{\mylist}% potty should be removed
\listfront{\mylist}% sam <- as expected
\end{document}
我很惊讶 etoolbox 没有为此目的提供“pop”,因为使用\listgremove
看起来可能非常低效,但我检查了宏跟踪,我发现它基于使用\ifinlist
分隔宏,而不是逐项检查,此外它只删除第一个找到的项目(文档对此并不清楚,但我从检查扩展中得出结论)。
请注意,LaTeX 内核已经有内置工具\@car
,\@cdr
和\@tfor
(更不用说 LaTeX3 现在合并的层......)您可以使用它来构建自己的,但我想etoolbox
如果您打算调用它的话,使用它来说是合乎逻辑的\dolistloop
。
这是现在使用内部 etoolbox 结构的代码。幸运的是,它非常简单明了,但如果将来发生变化,此代码将被破坏。
\documentclass{article}
\usepackage{etoolbox}
% this command is only good for typesetting,
% it does not work expandably
\newcommand{\listfront}[1]{%
\renewcommand{\do}[1]{##1\listbreak}%
\dolistloop{#1}%
}
\makeatletter
\begingroup
% definition of a "popfront" as per OP command name
% it removes the first item globally
\catcode`\|=3 % internal separator used by etoolbox
\gdef\listpopfront#1{%
\expandafter\listpopfront@i#1\@nil{#1}%
}
\long\gdef\listpopfront@i#1|#2\@nil#3{\long\gdef#3{#2}}
% we also define for the fun an expandable \listexpandablefront
% now that we are using internals of etoolbox
\gdef\listexpandablefront#1{%
\expandafter\listexpandablefront@i#1\@nil
}
\long\gdef\listexpandablefront@i#1|#2\@nil{#1}
\endgroup
\makeatother
\begin{document}
\newcommand{\mylist}{}%
\listgadd{\mylist}{potty}%
\listgadd{\mylist}{sam}%
% \show\mylist
\listfront{\mylist}% potty <- as expected
\listpopfront{\mylist}% potty should be removed
% \show\mylist
\listfront{\mylist}% sam <- as expected
\edef\foo{\listexpandablefront{\mylist}}
\texttt{\meaning\foo}
\end{document}
答案2
您似乎想要 FIFO 列表。我会使用expl3
而不是etoolbox
;请注意,列表名称没有反斜杠,这避免了选择命令名称的问题。
\documentclass{article}
\ExplSyntaxOn
%%% the user level commands
% declare a list and optionally add items
\NewDocumentCommand{\declarelist}{mo}
{
\daedsidog_list_declare:n { #1 }
\IfValueT{#2}
{
\daedsidog_list_gadd:nn { #1 } { #2 }
}
}
% add items to a list
\NewDocumentCommand{\listgadd}{mm}
{
\daedsidog_list_gadd:nn { #1 } { #2 }
}
% deliver the front item (this is expandable)
\NewExpandableDocumentCommand{\listfront}{m}
{
\daedsidog_list_front:n { #1 }
}
% pop the front item
\NewDocumentCommand{\listpopfront}{m}
{
\daedsidog_list_popfront:n { #1 }
}
%%% the internal functions
% declare a list
\cs_new_protected:Nn \daedsidog_list_declare:n
{
\seq_new:c { g__daedsidog_list_#1_seq }
}
% add items to a list
\cs_new_protected:Nn \daedsidog_list_gadd:nn
{
\clist_map_inline:nn { #2 }
{
\seq_gput_right:cn { g__daedsidog_list_#1_seq } { ##1 }
}
}
% deliver the front item
\cs_new:Nn \daedsidog_list_front:n
{
\seq_item:cn { g__daedsidog_list_#1_seq } { 1 }
}
% pop the front item
\cs_new_protected:Nn \daedsidog_list_popfront:n
{
\seq_gpop_left:cN { g__daedsidog_list_#1_seq } \l_tmpa_tl
}
\ExplSyntaxOff
\declarelist{mylist}[potty,sam]
% could also be
%\declarelist{mylist}
%\listgadd{potty,sam}
% or
%\declarelist{mylist}
%\listgadd{potty}
%\listgadd{sam}
\begin{document}
\listfront{mylist}% potty <- as expected
\listpopfront{mylist}% potty should be removed
\listfront{mylist}% potty <- expected sam!
\end{document}
您可以一次添加多个项目(声明列表时也可以)。