# Iterator-like command, where each use expands to an item from list defined earlier

What is the simplest way to create an iterator-like macro (in the functional programming sense) in pdfLaTeX?

I'd like to predefine a list of elements (to simplify we can assume that it is plain string, e.g. [C1, C2, C3], or [ad36bf, dea63f, 78f091]), and create a macro which would iterate over this list, i.e. each its use would get new element from the list. The iterator should error out if it tries to access more elements that there is on the list, or should return empty contents.

For example I would like to have

\deflist{A,B,C,D} % it doesn't need to use comma as separator

% ...

\el something \el xx \el


to produce

A something B xx C

I want to use this macro to automatically name / number nodes in graph created with TikZ/PGF...

It's a breeze with expl3:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\deflist}{O{,}m}
{
\seq_set_split:Nnn \l_narebski_list_seq { #1 } { #2 }
}

\NewDocumentCommand{\el}{}
{
\seq_item:Nn \l_narebski_list_seq { 1 }
\seq_pop_left:NN \l_narebski_list_seq \l_narebski_waste_tl
}

\seq_new:N \l_narebski_list_seq
\tl_new:N \l_narebski_waste_tl
\ExplSyntaxOff

\begin{document}

\deflist{A,B,C,D}

\el{} something \el{} xx \el{}

\deflist[-]{A-B}

\el{} something \el{} xx \el{}

\end{document}


The input is split into a sequence (spaces around the separator, that can be changed as an optional argument to \deflist, are trimmed off); at each call of \el the first item is delivered and then popped off the sequence.

A check for emptyness of the sequence can be easily added:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\deflist}{O{,}m}
{
\seq_set_split:Nnn \l_narebski_list_seq { #1 } { #2 }
}

\NewDocumentCommand{\el}{}
{
\seq_pop_left:NN \l_narebski_list_seq \l_narebski_next_tl
% if the sequence is empty, the token list will contain \q_no_value
\quark_if_no_value:VTF \l_narebski_next_tl
{ $\langle$empty$\rangle$ }
{ \tl_use:N \l_narebski_next_tl }
}

\seq_new:N \l_narebski_list_seq
\tl_new:N \l_narebski_next_tl
\cs_generate_variant:Nn \quark_if_no_value:nTF { V }
\ExplSyntaxOff

\begin{document}

\deflist{A,B,C,D}

\el{} something \el{} xx \el{}

\deflist[-]{A-B}

\el{} something \el{} xx \el{}

\end{document}


Instead of printing <empty>, the “true” part can be modified to issue a warning or an error.

In this case the items are space, not comma separated. If you want an item with spaces in it, enclose the whole phrase in braces, such as \deflist{A {B is the one} C D}.

A new invocation of \deflist resets the counter and reconstitutes the list.

\documentclass{article}
\newcommand\deflist[1]{\setcounter{itcount}{0}\getargsC{#1}}
\newcounter{itcount}
\newcommand\el{\stepcounter{itcount}\ifnum\value{itcount}>\narg\else%
\csname arg\romannumeral\value{itcount}\endcsname\ \fi}
\begin{document}
\deflist{A B C D} % it doesn't need to use comma as separator
% ...
\el something \el xx \el

\deflist{A {B is the one} C D}
\el something \el xx \el

\deflist{A B} % it doesn't need to use comma as separator
\el something \el xx \el
\end{document}