I've been wondering about the various methods available for looping over a comma separated list and the like. In particular, I was wondering about their various strengths and weaknesses. In other words, I was wondering about such things as the following (but not solely limited to this list):
- whether or not they're expandable,
- how they handle empty items,
- how they handle extraneous leading and trailing spaces
- whether you can use
\def/\edefor need to use\gdef/\xdefto save information from within the loop for later use.
In no particular order, here's a list of looping methods I'm familiar with. In the following list \current@item represents a macro, taking one argument, for formatting the current item in iteration.
Using commands from the 2ekernal:
%% \@for
\def\@for@myloop#1{%%
\@for \x:=#1 \do{\current@item \x}}
%% \@tfor (not a comma separated list--probably shouldn't be here)
\def\@tfor@myloop#1{%%
\@tfor \x:=#1 \do{\if,\x\relax\else\current@item \x\fi}}
Using etoolbox package
%% `etoolbox`: need to be careful whether passed a macro:
%% in that case expansion may be necessary to that the
%% delimiters are visible to `\forcsvlist`
\def\etoolbox@myloop#1{%%
\expandafter\forcsvlist
\expandafter\current@item
\expandafter{#1}}
Using pgffor package
%% pgffor
\def\pgffor@myloop#1{%%
\foreach \x in {#1} {\current@item \x}}
A homebrew method:
%% version a la `ae`
\def\@ae@myloop#1,#2\@nil{%%
\current@item{#1}%%
\expandafter\ifx\expandafter\relax\detokenize{#2}\relax\else
\@ae@myloop#2\@nil
\fi
}
\def\ae@myloop#1{%%
\@ae@myloop#1,\@nil
}
Then there are also the various expl3 methods such as (there are quite a few, so this is hardly exhaustive):
\tl_map_inline:nn
\tl_map_function:Nn
\clist_map_inline:Nn
\seq_map_inline:Nn
Here is a MWE illustrating the results of each of these (including one LaTeX3 version):
\documentclass{article}
\usepackage[margin=0.5in,paperheight=15in]{geometry}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{pgffor}
\usepackage{enumitem}
\makeatletter
\def\my@item@count{0}
\def\step@my@counter{\xdef\my@item@count{\number\numexpr\my@item@count+1\relax}}
%% \rules to emphasize how spaces are seen and treated!
\def\current@item#1{\step@my@counter\item \rule{0.4pt}{2ex}#1\rule{0.4pt}{2ex}}
%% `etoolbox`
\def\etoolbox@myloop#1{%%
\forcsvlist \current@item {#1}}
%% but if passed a macro, then it first needs to be expanded so the delimiters are visible to `\forcsvlist`. You'll need to write
%% \expandafter\forcsvlist \expandafter\current@item \expandafter{#1}}
%% \@for
\def\@for@myloop#1{%%
\@for \x:=#1 \do{\current@item \x}}
%% \@tfor
\def\@tfor@myloop#1{%%
\@tfor \x:=#1 \do{\current@item \x}}
%% pgffor
\def\pgffor@myloop#1{%%
\foreach \x in {#1} {\current@item \x}}
%% version a la `ae`
\def\@ae@myloop#1,#2\@nil{%%
\current@item{#1}%%
\expandafter\ifx\expandafter\relax\detokenize{#2}\relax\else
\@ae@myloop#2\@nil
\fi
}
\def\ae@myloop#1{%%
\@ae@myloop#1,\@nil
}
\def\listoffruit#1#2#3{%%
\def\my@item@count{0}%%
\noindent
List of type \texttt{#1}: \parbox[t]{3in}{\raggedright#3}
\begin{itemize}[topsep=4pt,itemsep=2pt]
\csname#1@myloop\endcsname{#2}%%
\end{itemize}
Total number of bulleted items: \my@item@count
\par \vspace{2ex}\hrule\par \vspace{2ex}
}
\ExplSyntaxOn
\NewDocumentCommand{\expl@myloop}{ m }
{
\clist_map_inline:nn{#1}{\current@item {##1}}
}
\ExplSyntaxOff
\makeatother
\def\apples{apples}
\def\bananas{bananas}
\def\cherries{cherries}
\begin{document}
\listoffruit{etoolbox}{apples,, oranges, bananas ,cherries}{Ignores leading spaces and empty items. Trailing spaces not ignored.}
\listoffruit{@for}{apples,, oranges, bananas ,cherries}{Empty lines and trailing or leading spaces not ignored. Something goes on with last item in list.}
\listoffruit{@tfor}{\apples,{} {oranges}\bananas\cherries}{Spaces ignored, all other token respected, bracketed tokens treated as one.}
\listoffruit{pgffor}{apples,, oranges, bananas ,cherries}{Ignores leading spaces, empty items and trailing spaces not ignored.}
\listoffruit{ae}{apples,, oranges, bananas ,cherries}{Leading or trailing spaces not ignored. Empty items not ignored.}
\listoffruit{expl}{apples,, oranges, bananas ,cherries}{Trailing or leading spaces ignored. Empty items ignored.}
\end{document}

Issues I'm aware of:
- I believe
\@foris not expandable, \cslist_map_inline:nnis expandable but with limitations: i.e., it is not expandable in anf-type argument.pgffor's\foreachloop in executed within a group. So you need to use\gdefor\xdegto save information from within the group for later use. I've not fully explored which others of the loops presented here have a similar short-coming (not sure that's the right choice of word). I have no idea whether\foreachis expandable or not.- Some methods handle their lists rather nicely whether passed explicitly or implicitly via a macro. For example,
pgffor's\foreachknows what do to with a list passed via a macro.etoolbox's\forcsvlistneeds that macro to first be expanded: hence the reason my first illustration of a\forcslistis as complicated as it is.
So what I'm interested in here is:
- Responses which address the strengths and weaknesses of the different approaches presented here as itemized at the beginning of this post, but not necessarily limited to those suggestions since I may be unaware of other important issues.. For example, I'm not really sure which are expandable.
- Responses which introduce other methods for iterating over a list of items along with their known weaknesses and strengths.
- Responses which can illustrate realistic examples for which one would want to use such a loop in an expandable context
- Reponses which illustrate how one can save information gathered from within the group for later use.


forloop. – marczellm Oct 27 '13 at 07:50forloopis for looping a counter: much more likeexpl3's\int_step_function:nnnNor similar. – Joseph Wright Oct 27 '13 at 08:12\foreachsaved me asking a question. I'm on a steep learning curve withtikzandpgfplotsand as yet just getting started on loops and your question is right up my alley. Can't wait to see the answers. – Geoff Pointer Oct 27 '13 at 09:28\expandafter\ifx\relax\detokenize{#1}\relax? The shorter version\if\relax\detokenize{#1}\relaxis safe and reliable. About the bulk of the question: remove the braces around the items and try also with leading and trailing spaces. – egreg Oct 27 '13 at 10:02\ifxbecause I understand it better than\fi. I'm not really sure what you mean in your suggestion for improving the readability of the question. Could you post a link to another question that does something similar to what you're trying to suggestion? – A.Ellett Oct 27 '13 at 14:50\@tfor. – A.Ellett Oct 27 '13 at 15:02\@tforis really out of place here, because it doesn't manage comma separated lists. – egreg Oct 27 '13 at 15:56\pgfplotsforeachungrouped, which comes with thepgfplotspackage. As I understand it, it's intended to be identical to the\foreachcommand frompgfforexcept that it is not executed within a group. However, I'm not qualified to understand any more subtle differences. Also, short of (possibly) copying code from the source, I don't know of a way to get this method without using the entirepgfplotspackage, which dragsTikZin with it. – Charles Staats Oct 27 '13 at 17:15pgfplotsis active on TeX.SE, I'm going to wait a bit to see if he responds first. In the meantime, here's a potentially relevant answer he wrote http://tex.stackexchange.com/a/17817/484 as well as another answer http://tex.stackexchange.com/a/43355/484 by a different author demonstrating one use of\pgfplotsforeachungrouped. – Charles Staats Oct 27 '13 at 17:25\multido? – kiss my armpit Nov 01 '13 at 18:37