# What is the best way to scan over a list of somethings?

It seems that a common operation needed when defining new commands is to scan over a list of arguments (separated e.g. by a comma, but maybe by something else) and do something with each argument in the list, find the last one, or whatever.

For example to write commands that look like \Command{a,b,c} or \Command{c.d.e} and do something with each a, b, and c. See e.g. questions on defining a list of operators and ignoring even numbered inputs.

Some solutions have been posted there, but what would be the best idiom to perform such kind of operations? LaTeX's \@for looks very nice, but is it possible to use it to scan anything other than comma-separated lists?

-

I have not progressed to the level of processing a list myself but I have been using etoolbox by Philipp Lehman for some other TeX programming tasks I am doing. I believe 3.7 List processing should give you a good solution.

For example (on a recent version of etoolbox) you can write:

\DeclareListParser*{\myfor}{;}
\myfor{\fbox}{item1; item2; item3}

-
Thanks for the reference! It does have some nice commands to process a list of arguments. If you don't mind I can edit your answer to include an example. –  Juan A. Navarro Aug 6 '10 at 20:53

I was hoping someone to post a better/nicer solution, but so far this seems to be the best one I've seen.

\def\do@scan#1:{%
\ifx#1\relax
\let\next\relax
\else
\DoSomethingWith{#1}\let\next\do@scan
\fi\next
}
\newcommand{\scanlist}[1]{\do@scan#1:\relax:}


Of course instead of : one can use , or any other sensible separator.

-
I agree that this is a very good solution, since it does not require any other package at all and needs very few lines of code nevertheless. –  Rupert Jones Mar 25 '11 at 14:32

Here is an LPEG based solution. This is written in ConTeXt, but should be easy to modify for LuaLaTeX

\unprotected\def\ProcessListWithDelim#1[#2]#3% delim list command
{\ctxlua{userdata.ProcessListWithDelim(\!!bs#1\!!es, \!!bs#2\!!es, \!!bs\noexpand#3\!!es)}}

\startluacode
userdata = userdata or {}

function userdata.ProcessListWithDelim(delim, list, command)
local splitter = lpeg.Ct(lpeg.splitat(lpeg.P(delim)))
local items    = lpeg.match(splitter, list)

for i=1,#items do
tex.sprint(tex.ctxcatcodes, command .. '{' .. items[i] .. '}')
end
end
\stopluacode

\def\ShowItem#1{>>>#1<<<\crlf}

\def\CommandA#1{\ProcessListWithDelim,[#1]\ShowItem}

\def\CommandB#1{\ProcessListWithDelim{:}[#1]\ShowItem}

\starttext
\CommandA{A,Comma,Separated,List}

\CommandB{A:Colon:Separated:List}
\stoptext

-

In ConTeXt, list processing is done using \processcommalist. Suppose you want to apply the macro \doCommand over each list element passed to \Command. The following definition of \Command does this:

\def\Command#1{\processcommalist[#1]\doCommand}


If the list may contain macros, like

\def\Arguments{a,b,c}
\Command{\Arguments,d,e,f}


then you can use \processcommacommand, like

\def\Command#1{\processcommalistcommand[#1]\doCommand}


There are a some faster alternatives, \rawprocesscommalist and \rawprocesscommacommand but they have certain limitations. See the ConTeXt wiki page on list processing for details.

To process a list with an arbitrary separator, \processlist may be used. \processlist takes 5 arguments: beginning of list marker, end of list marker, element separator, command to apply to each element, and the list. For example, a command \Command[a:b:c] that uses colon as the separator, can be defined as

\def\Command{\processlist[]:}

-
but what about lists separated by a character other than a comma? –  Juan A. Navarro Oct 14 '10 at 14:58
\processlist can be used to process a list with a particular separator. I added that information in the answer. –  Aditya Oct 21 '10 at 1:11
Nice, thank you! –  Juan A. Navarro Oct 21 '10 at 9:02

Here's a complete example using the \docsvlist command provided by etoolbox. The example introduces a package called csvfont and its usecsvfont environment. The font and formatting of this environment can be set using the package/environment options font (which resets the font definition) and font+ (which appends the font definition). Both options may take a comma-separated list of values; as individual values one may specify the names (without preceding backslash) of LaTeX's font-switching/formatting commands. (This syntax is used in the upcoming version 0.1b of my quoting package.)

\RequirePackage{filecontents}

\begin{filecontents}{csvfont.sty}
\ProvidesPackage{csvfont}

\RequirePackage{etoolbox,kvoptions}
\SetupKeyvalOptions{family=csf,prefix=csf@}

\newcommand*{\csvfont}{}

\define@key{csf}{font}{%
\def\csvfont{}%
\renewcommand*{\do}[1]{\appto{\csvfont}{\csname ##1\endcsname}}%
\docsvlist{#1}%
}
\define@key{csf}{font+}{%
\renewcommand*{\do}[1]{\appto{\csvfont}{\csname ##1\endcsname}}%
\docsvlist{#1}%
}

\ProcessKeyvalOptions*

\newenvironment{usecsvfont}[1][]{\setkeys{csf}{#1}\csvfont}{}

\endinput
\end{filecontents}

\documentclass{article}

\usepackage[font={small,itshape}]{csvfont}

\usepackage{lipsum}

\begin{document}

\begin{usecsvfont}
\lipsum[1]
\end{usecsvfont}

\begin{usecsvfont}[font+={bfseries,raggedright}]
\lipsum[1]
\end{usecsvfont}

\begin{usecsvfont}[font={bfseries,raggedright}]
\lipsum[1]
\end{usecsvfont}

\end{document}


-
...that pushed you over the 50K edge. Glad I could be the one. :) –  Werner Feb 24 '12 at 18:35

Since Morbusg's answer pushed that question to the top, let me add a LaTeX3 answer. The idea is to convert the list to an internal structure called a sequence, and then map over that sequence \l_MyMap_seq.

\documentclass{article}
\usepackage{expl3, xparse}
\ExplSyntaxOn
\seq_new:N \l_MyMap_seq
\NewDocumentCommand{\MyMap}{O{,}mm}
{
\seq_set_split:Nnn \l_MyMap_seq {#1} {#2}
\seq_map_inline:Nn \l_MyMap_seq {#3}
}
\ExplSyntaxOff
\begin{document}
\MyMap{a,b,c}{\fbox{#1} }
\begin{tabular}{c}
\MyMap[:]{a:b:c}{#1\\}
\end{tabular}
\end{document}


The first (optional) argument is the delimiter, by default a comma. The second argument is the list, and the third is a function, taking each item of the list as #1.

The xparse package also provides \SplitList, which can be used as

\NewDocumentCommand {\foo} { >{\SplitList{.}} m m } { \tl_map_inline:nn {#1}{#2} }


hard-coding the delimiter in the definition of \foo.

-

Here's my solution (borrowed form Kevin Walker):

% tricky way to iterate macros over a list
\def\semicolon{;}
\def\applytolist#1{
\expandafter\def\csname multi#1\endcsname##1{
\def\multiack{##1}\ifx\multiack\semicolon
\def\next{\relax}
\else
\csname #1\endcsname{##1}
\def\next{\csname multi#1\endcsname}
\fi
\next}
\csname multi#1\endcsname}


And some examples of its use:

% \def\cA{{\cal A}} for A..Z
\def\calc#1{\expandafter\def\csname c#1\endcsname{{\mathcal #1}}}
\applytolist{calc}QWERTYUIOPLKJHGFDSAZXCVBNM;

% \DeclareMathOperator{\pr}{pr} etc.
\def\declaremathop#1{\expandafter\DeclareMathOperator\csname #1\endcsname{#1}}

-
This is very similar to the proposed solutions posted in the original threads (see the question), I wanted to know if there is anything better. Moreover, I would like to process lists of arguments given as \Command{a,b,c} or \Command{a:b:c}. –  Juan A. Navarro Jul 27 '10 at 16:39

Plain example of “Lists in TeX's mouth”, lambda.sty (TUGboat article):

\catcode@=11
\input lambda.sty
\catcode@=12
\def\csnameafter#1#2{\expandafter#1\csname#2\endcsname}
\def\MathOp#1{\csnameafter\def{#1}{\mathop{\it #1}}%
#1} % show it, too
\def\Odd#1{\TeXif{\ifodd#1 }}

\Show\Filter\Odd[1,2,3,4,5,6,7,8,9,10,11,12,13] % => [1,3,5,7,9,11,13]

\Show\Map\MathOp[Rep,Tet,Maps,Diff] $\Rep\Tet\Maps\Diff$
\bye

-