Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I want to know how I can store variables so I can iterate over them.

Say we have this input in the document:

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

Later in the document we write something like \outputinreverseorder and get “Input 3 is ‘third input’. Input 2 is ‘second input’. Input 1 is ‘first input’.” Writing something like \outputinorder gives the opposite order.

share|improve this question
2  
Depending on how you want it to behave exactly, you might want to have a look at Stack datastructure using LaTeX , they deal with many issues, like datastructures themselves, verbatim text in the arguments etc. –  Andreas Wallner May 17 '12 at 10:15
add comment

5 Answers

up vote 14 down vote accepted

Here's an implementation with 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}

Each \inputcommandname adds globally its argument to a sequence which we can use for printing in direct order or in reverse order by reversing it.

The output is

Here is direct order:
Input 1 is ‘first input’
Input 2 is ‘second input’
Input 3 is ‘third input’

Here is reverse order:
Input 3 is ‘third input’
Input 2 is ‘second input’
Input 1 is ‘first input’


Due to the changes made to expl3 in Summer 2012, in the code above \seq_length should be replaced by \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
   }
 }
share|improve this answer
add comment

You can use \@namedef and \@nameuse to define the input values to internal macros numbered by a running counter. This counter then can be used to iterate over the elements.

Alternatives might be the stack package which AFAIK provides functionality like this as well. Also the etoolbox package provides macros to define lists and iterate over them. However, I didn't saw anything about reversing the order.


Here some principle code:

\documentclass{article}

\newcounter{inputcommandname}
\makeatletter
\newcommand\inputcommandname[1]{%
    \stepcounter{inputcommandname}%
    \@namedef{inputcommandname@\theinputcommandname}{#1}%
}
\newcommand\getinputcommandname[1]{%
    \@nameuse{inputcommandname@\number#1}%
}

\newcommand\outputinreverseorder{%
    \@tempcnta=\value{inputcommandname}
    \loop
      \@nameuse{inputcommandname@\number\@tempcnta}%
      \advance\@tempcnta by -1
      \ifnum\@tempcnta>0
        \separator
    \repeat
}

\newcommand\outputinorder{%
    \@tempcnta=1
    \loop
      \@nameuse{inputcommandname@\number\@tempcnta}%
      \ifnum\@tempcnta<\value{inputcommandname}%
        \advance\@tempcnta by 1
        \separator
    \repeat
}

\newcommand\separator{, }
\makeatother

\begin{document}

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

% Second input:
\getinputcommandname{2}

% In reverse order
\outputinreverseorder

% In order
\outputinorder

\end{document}

This gives:

second input
third input, second input, first input
first input, second input, third input
share|improve this answer
add comment

And here comes a LuaTeX solution. It's ConTeXt flavoured, but it can be easily adapted to LaTeX as well.

\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

It simply stores the values in a table and outputs the table in the requested order.

screenshot

share|improve this answer
add comment

I suppose this isn't so different from Martin's but here is a plain TeX solution

enter image description here

\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
share|improve this answer
    
+1 for the reversing wizardry in \outputinreverseorder and for using a stack. I would have saved also the \count0 values in the stack, to avoid \advanceing it on the pop. –  Ahmed Musa May 17 '12 at 15:34
add comment

Here is an extension/generalization of David Carlisle's solution. (1) Several stacks could be created for different purposes using the command \inputcommandnames; (2) the command \inputcommandnames or \inputcommandname can be called with more than one command name for each stack; the commands \outputinnormalorder and \outputinreverseorder can be called with more than one stack name; (4) the stack counter is called only on push, and not on pop. See the examples.

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

enter image description here

share|improve this answer
1  
Maybe you could elaborate a bit what exactly is your extension/generalization? –  Daniel May 17 '12 at 19:14
    
@Daniel: I have added some note. –  Ahmed Musa May 17 '12 at 20:33
    
+1 for a nice solution :-) –  Daniel May 18 '12 at 6:54
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.