# Is there a \foreach function that works in the preamble?

Tikz/PGF has an extremely useful implementation of \foreach, which allows for instance the construction

\foreach \x / \y in {1/a,2/b,3/c,4/d} {\x is a lot like \y}


in which you can iterate over a pair of lists. This command only works within a tikz environment, so in particular doesn't work in the preamble, where I want to use it for defining a huge number of very similar looking macros, with say \newcommand{\task\x}{\function\y}; (really I'm defining new shapes in tikz, each of which is fifty or more lines of code, so just repeating it all a few hundred times is genuinely impractical).

Is there a function in tex that will easily do something similar? I am aware that I could hack together this functionality using ForArray functions or nested forloops, but the results seemed like they would be comparatively inelegant, and I hoped someone here might have a clean approach (or a clean implementation using arrays or loops).

-
\foreach doesn't have to be in a tikzpicture, it also works in the preamble. The problem is that you won't be able to define new commands inside the loop, as each iteration is executed inside a local group, so definitions won't be global. Note also that you have the syntax wrong, it should be in {1/a,2/b,3/c,4/d}. Maybe you could add some more detail about what kinds of shapes you're trying to define? I'm sure that if they can be defined in a for-loop, they can also be parametrised, which would probably be a better approach. –  Jake May 18 '11 at 14:50
You could either use \gdef or say \newcommand\foo{...}\global\let\foo\foo, but in both cases you would need to expand \x and \y before the definition. –  Martin Scharrer May 18 '11 at 14:53
With regard to the grouping of \foreach, take a look at the answers to this question of mine: tex.stackexchange.com/q/15204/86 –  Loop Space May 18 '11 at 18:00

You can use \xdef (global expanding definition) together with \csname ... \endcsname inside \foreach in the preamble. It works in the preamble but encloses the content in a group which requires the global definition. The loop "variables" (macros) must be expanded before/during the definition, otherwise the macros will just contain \y and not its current content.

Here an example how to define macros like \mymacroa, \mymacrob, etc., which will contain a call to \dostuff which gets the \y content.

\documentclass{article}

\usepackage{pgffor}

\foreach \x/\y in {a/1,b/2,c/3,d/4} {
\expandafter\xdef\csname mymacro\x\endcsname{%
\noexpand\dostuff{\y}%
}%
}

\newcommand{\dostuff}[1]{\texttt{(#1)}}

\begin{document}

\mymacroa

\mymacrob

\mymacroc

\mymacrod

\end{document}


If you want to do something different like defining a PGF shape than it would be better if you simply accumulate the required macro calls with the loop variables expanded and execute the accumulator afterwards.

The following code adds \dostuff{<x>}{<y>} to \mycommands which is executed after the loop outside any group. It then contains \dostuff {a}{1}\dostuff {b}{2}\dostuff {c}{3}\dostuff {d}{4}.

\documentclass{article}

\usepackage{pgf}
\usepackage{pgffor}
\usepackage{etoolbox}

\newcommand{\mycommands}{}

\newcommand{\dostuff}[2]{%
\pgfdeclareshape{#1}{%
\anchor{#2}{...}%
}%
}

\foreach \x/\y in {a/1,b/2,c/3,d/4} {%
\xappto{\mycommands}{\noexpand\dostuff{\x}{\y}}%
}
%\show\mycommands
\mycommands

\begin{document}

\end{document}

-
With etoolbox, I'd get rid of pgffor. It's somewhat hard to use the expansion tricks. –  Leo Liu May 18 '11 at 15:14
@Leo: If you use a helper macro like \dostuff which simply accepts the expanded macros there shouldn't be any issue with the expansion. If \x and \y are complex they are better written as \expandonce\x and \expandonce\y. –  Martin Scharrer May 18 '11 at 15:32
\xdef, \noexpand, \expandonce... I can do it, but often make mistakes. Expansion is always a blackhole in TeX. That's why I don't like it. I prefer \docsvlist or \forcsvlist, which take the loop variable a argument — then there's no expansion issue at all. –  Leo Liu May 18 '11 at 15:47
Thanks for the explanations. I wish I'd known this functionality ages ago. –  Chris May 22 '11 at 20:09

pgffor does work outside tikzpicture environment, although it is not robust enought for some applications.


The other problem is due to pgffor. It is executed in a group, and you must expand the variable when define a new macro using it.

Example solution, you must control the expansion of \x and \y carefully:

\documentclass{article}
\usepackage{pgffor}
\foreach \x/\y in {a/1,b/2,c/3} {
\expandafter\xdef\csname cmd\x\endcsname{number \y}
}
\begin{document}
\cmda, \cmdb, \cmdc
\end{document}


Another solution using etoolbox, this is preferred:

\documentclass{article}
\usepackage{etoolbox}
\def\dodo#1/#2{\csdef{cmd#1}{number #2}}
\def\do#1{\dodo#1}
\docsvlist{a/1,b/2,c/3}
\begin{document}
\cmda, \cmdb, \cmdc
% we obtain: number 1, number 2, number 3
\end{document}

-
Thanks, I'll try this approach out too. –  Chris May 22 '11 at 20:10

With the catoptions package the auxiliary \dodo is not necessary and you can also use an arbitrary list separator. Also, each element of the list is first trimmed of spurious leading and trailing spaces before \do takes effect.

\documentclass{article}
\usepackage{catoptions}[2011/10/22]

\begin{document}

\def\do#1/#2{\csndef*{cmd#1}{number #2}}
\dofunclist{a/1, b/2, c/3}

%\dofunclist[;]{a/1; b/2; c/3}
\cmda, \cmdb, \cmdc

\end{document}

-