我如何存储变量并对其进行迭代?

我如何存储变量并对其进行迭代?

我想知道如何存储变量以便可以对它们进行迭代。

假设我们在文档中有这样的输入:

\inputcommandname{first input}
\inputcommandname{second input}
\inputcommandname{third input}

稍后在文档中我们写入类似的内容\outputinreverseorder并得到“输入 3 是‘第三个输入’。输入 2 是‘第二个输入’。输入 1 是‘第一个输入’。”写入类似的内容\outputinorder会给出相反的顺序。

答案1

以下是一个实现expl3

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

% first of all we define the user level commands
\NewDocumentCommand{\inputcommandname}{ m }{ \malmedal_input_add:n { #1 } }
\NewDocumentCommand{\outputinorder}{ }{ \malmedal_output_direct: }
\NewDocumentCommand{\outputinreverseorder}{ }{ \malmedal_output_reverse: }

% allocate some variables:
% 1. a sequence for global storage of the inputs;
% 2. a temporary sequence when we need to reverse;
% 3. a counter (integer variable)
\seq_new:N \g_malmedal_input_seq
\seq_new:N \l_malmedal_temp_seq
\int_new:N \l_malmedal_count_int

% store globally an input in the sequence    
\cs_new:Npn \malmedal_input_add:n #1
 {
  \seq_gput_right:Nn \g_malmedal_input_seq { #1 }
 }

% how to output in direct order; we simply do a mapping function calling
% \malmedal_print:n after incrementing the counter
\cs_new_protected:Npn \malmedal_output_direct:
 {
  \int_zero:N \l_malmedal_count_int
  \seq_map_inline:Nn \g_malmedal_input_seq
   {
    \int_incr:N \l_malmedal_count_int
    \malmedal_print:n { ##1 }
   }
 }

% how to output in reverse order; first we store a copy of the main
% sequence in the temporary one, that we reverse; then we set the
% integer variable to the length of the sequence; finally we map the
% temporary sequence, decrementing the counter after having printed
% its contents
\cs_new_protected:Npn \malmedal_output_reverse:
 {
  \seq_set_eq:NN \l_malmedal_temp_seq \g_malmedal_input_seq
  \seq_reverse:N \l_malmedal_temp_seq
  \int_set:Nn \l_malmedal_count_int { \seq_length:N \l_malmedal_temp_seq }
  \seq_map_inline:Nn \l_malmedal_temp_seq
   {
    \malmedal_print:n { ##1 }
    \int_decr:N \l_malmedal_count_int
   }
 }

% the printing macro; change here for adapting to your wishes
\cs_new:Npn \malmedal_print:n #1
 {
  Input ~ \int_to_arabic:n { \l_malmedal_count_int } ~ is ~ `#1' \par
 }
\ExplSyntaxOff

\begin{document}

\inputcommandname{first input}
\inputcommandname{second input}
\inputcommandname{third input}

Here is direct order:

\outputinorder

\bigskip

Here is reverse order:

\outputinreverseorder

\end{document}

每个都\inputcommandname将其参数全局添加到一个序列中,我们可以使用该序列按正序打印,也可以通过反转该序列以相反的顺序打印。

输出为

以下是直接顺序:
输入 1 是“第一个输入”
输入 2 是“第二个输入”
输入 3 是“第三个输入”

以下是相反的顺序:
输入 3 是“第三个输入”
输入 2 是“第二个输入”
输入 1 是“第一个输入”


由于expl32012 年夏季对 所做的更改,上述代码\seq_length应替换为\seq_count

\cs_new_protected:Npn \malmedal_output_reverse:
 {
  \seq_set_eq:NN \l_malmedal_temp_seq \g_malmedal_input_seq
  \seq_reverse:N \l_malmedal_temp_seq
  \int_set:Nn \l_malmedal_count_int { \seq_count:N \l_malmedal_temp_seq }
  \seq_map_inline:Nn \l_malmedal_temp_seq
   {
    \malmedal_print:n { ##1 }
    \int_decr:N \l_malmedal_count_int
   }
 }

答案2

现在有了 LuaTeX 解决方案。它具有 ConTeXt 风格,但也可以轻松适应 LaTeX。

\startluacode

  userdata = { }
  userdata.list = { }
  local list = userdata.list

  userdata.addtolist = function (item)
    userdata.list[#list+1] = item
  end

  userdata.outputinorder = function ()
    for i=1, #list do
      context(list[i])
      context.crlf()
    end
  end

  userdata.outputinreverseorder = function ()
    for i=#list, 1, -1 do
      context(list[i])
      context.crlf()
    end
  end

\stopluacode

\define[1]\inputcommandname{\ctxlua{userdata.addtolist("#1")}}
\define   \outputinorder{\ctxlua{userdata.outputinorder()}}
\define   \outputinreverseorder{\ctxlua{userdata.outputinreverseorder()}}

\starttext
  \inputcommandname{first input}
  \inputcommandname{second input}
  \inputcommandname{third input}

  \outputinorder
  \blank
  \outputinreverseorder
\stoptext

它只是将值存储在表中并按照要求的顺序输出表。

截屏

答案3

我想这和 Martin 的没什么不同,但这是一个简单的 TeX 解决方案

在此处输入图片描述

\def\stack{}
\def\stackcount{0}

\def\inputcommandname#1{{%
\let\xdo\relax
\count0=\stackcount\relax
\advance\count0 by 1
\xdef\stackcount{\the\count0}%
\toks0{\xdo{#1}}%
\toks2\expandafter{\stack}%
\xdef\stack{\the\toks2 \the\toks0 }}}


\def\outputinorder{{\count0=0
\def\xdo##1{\advance\count0 by 1
Input \the\count0 \space is: `##1'. }%
\stack}}

\def\outputinreverseorder{{%
\def\xdo##1##2\midstack##3\empty{%
  ##2\midstack\xdo{##1}##3\empty}%
\stack\midstack\empty}}

\def\midstack{%
\count0=\stackcount
\def\xdo##1{%
Input \the\count0 \space is: `##1'. 
\advance\count0 by -1 }}



\inputcommandname{first input}
\inputcommandname{second input}
\inputcommandname{third input}


\outputinorder 


\outputinreverseorder 

\bye

答案4

这是 David Carlisle 解决方案的扩展/概括。(1) 可以使用命令 为不同目的创建多个堆栈;(2)可以使用多个命令名称为每个堆栈调用\inputcommandnames命令\inputcommandnames或;可以使用多个堆栈名称调用命令和;(4) 堆栈计数器仅在推送时调用,而不是弹出时调用。参见示例。\inputcommandname\outputinnormalorder\outputinreverseorder

\documentclass{article}
\usepackage{catoptions}
\makeatletter
\robust@def*\inputcommandnames{\cpt@testopt\@inputcommandnames{general}}
\newletcs\inputcommandname\inputcommandnames
% #1=stack name, #2=input name(s)
\robust@def*\@inputcommandnames[#1]#2{%
  \ifblankFT{#1}{%
    \@latex@info{No stack name given: using 'general' instead}%
  }{%
    % It is possible to iterate over stack names, but leave this for now:
    % the use case isn't yet apparent.
    \ifinsetTF,{#1}{%
      \@latexerr{List '#1' not allowed}\@ehd
    }{}%
  }%
  \ifcsndefTF{name@stack@#1}{}{\csn@def{name@stack@#1}{}}%
  \ifcsndefTF{name@stackcount@#1}{}{\csn@def{name@stackcount@#1}{0}}%
  \cptdocommalist{#2}{%
    \csn@edef{name@stackcount@#1}%
      {\the\numexpr\usename{name@stackcount@#1}+1}%
    \csn@edef{name@stack@#1}{%
      \expandcsnonce{name@stack@#1}\noexpand
      \do{\usename{name@stackcount@#1}}{\unexpanded{##1}}%
    }%
  }%
}
\robust@def*\outputinnormalorder{\@outputcommandnames{normal}}
\newletcs\outputcommandnames\outputinnormalorder
\robust@def*\outputinreverseorder{\@outputcommandnames{reverse}}
% #1=listing/printing order, #2=stack name(s)
\robust@def*\@outputcommandnames#1#2{%
  \cptdocommalist{#2}{%
    \begingroup
    \let\reserved@a\relax
    \ifcsndefTF{name@stack@##1}{%
      % If the stack is defined but it is currently empty, ignore it
      % (but issue a warning). A 'verbose' option for triggering the
      % warning will be useful here, but it hasn't been provided:
      \ifcsnnullFT{name@stack@##1}{}{%
        \@latex@info{Stack '##1' is empty}%
        \def\reserved@a####1\endgroup{\endgroup}%
      }%
    }{%
      \@latexerr{Stack '##1' is not defined}\@ehd
    }%
    \reserved@a
    \xifstrcmpTF{#1}{normal}{%
      \let\do\curroutputformat
      \csname name@stack@##1\endcsname
    }{%
      \def\name@sentinel####1\name@stop{%
        \let\do\curroutputformat####1%
      }%
      \def\do####1####2####3\name@sentinel####4\name@stop{%
        ####3\name@sentinel\do{####1}{####2}####4\name@stop
      }%
      \usename{name@stack@##1}\name@sentinel\name@stop
    }%
    \endgroup
  }%
}
% \commandnameoutputformat<input no.><input item>
\robust@def*\commandnameoutputformat{%
  % Skip any spurious spaces before opening brace:
  \begingroup
  \toks0{##1##2}%
  \def\reserved@a{%
    \expandafter\endgroup\expandafter\def\expandafter
    \curroutputformat\the\toks\expandafter0\expandafter{\the\toks1}%
  }%
  \afterassignment\reserved@a\toks1=%
}
% If the stack isn't initialized after use, it will start building
% from the last count whenever it is called:
\robust@def*\initializecommandstacks#1{%
  \cptdocommalist{#1}{%
    \csn@def{name@stackcount@##1}{0}%
    \csn@def{name@stack@##1}{}%
  }%
}
\newletcs\initializecommandstack\initializecommandstacks

% Set empty stack 'xx' for warning later:
\csn@def{name@stack@xx}{}
\makeatother

% Examples:
\begin{document}
\inputcommandname{first input (general),second input (general),third input (general)}
\inputcommandname[stack-1]{First Input (stack-1),Second Input (stack-1),Third Input (stack-1)}
\commandnameoutputformat{Input number #1 is: #2.\par}
Normal order Output:\par
\outputinnormalorder{general,stack-1}
\par\medskip
Reverse order Output:\par
\outputinreverseorder{general,stack-1}
\par\medskip
Normal order Output:\par
\outputinnormalorder{stack-1}
\par\medskip
Reverse order Output:\par
\outputinreverseorder{stack-1}
% Issue a warning for empty stack 'xx' and continue:
\outputcommandnames{xx}
\outputinreverseorder{general}
\end{document} 

在此处输入图片描述

相关内容