6

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...

6

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}

enter image description here

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}

enter image description here

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

|improve this answer|||||
3

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}
\usepackage{readarray}
\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}

enter image description here

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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