A mild variant on Caramdir's answer (more or less equivalent to the alternative):
\documentclass{article}
\usepackage{pgffor}
\newcommand*\minusminus[1]{--#1}
\newcommand*\initial[1]{#1\global\let\doit=\minusminus}
\let\doit=\initial
\begin{document}
\foreach \n in {1,...,5} {%
\doit{\n}%
}
\end{document}
The \doit
macro redefines itself after the first call and thereafter adds the en dash. This is sort of evil, but I had in mind something like calling a function pointer with a target that gets replaced, which is less evil.
Edit: And here is a solution that actually treats the last item specially.
\documentclass{article}
\usepackage{pgffor,etoolbox}
\newcommand*\last{}
\newcommand*\storage{}
\newcommand*\doit[1]{%
\xdef\storage{\expandonce\storage\noexpand\transform{\last}}%
\xdef\last{#1}%
}
\newcommand*\finalize{\storage\last}
\newcommand*\minusminus[1]{#1--}
\newcommand*\initial[1]{#1\global\let\transform=\minusminus}
\let\transform=\initial
\begin{document}
\foreach \n in {1,...,5} {
\doit{\n}
}
\finalize
\end{document}
What's happening is that each iteration of \doit
saves its argument and then adds the previous argument (which was saved) to the \storage
list, along with a directive to transform it. In the last iteration, the argument is saved but never added, which is done in \finalize
, but without the transformation.
Note the appearance of the "Carlisle wand", as Ahmed Musa described it, even in this method. The first (that is, zeroth) \last
should be ignored. You can even double this up (that is, have \transform
redefine itself to something else that then redefines itself) to get the first item, or indeed any specific number of initial items, to behave differently. And of course, you can do something to the last item as well, rather than nothing, as I did.
As far as I can tell, it is mathematically necessary to have the \finalize
step. You can't know you are at the end of the list until moving past it, so every item has to be processed late, and in particular the last item has to be processed "by hand". This is as automated as I can get it.
Edit: In response to Peter Grill's comment: there is actually a way to do \AtEndForeach
, though it's not pretty. I don't know why there is no mechanism to set this, since it is a no-op in the code:
\makeatletter
\let\pgffor@afterhook=\finalize
\makeatother
I suppose you could make this a macro:
\makeatletter
\newcommand\AtEndForeach{%
\def\pgffor@afterhook
}
\makeatother
\AtEndForeach{\finalize}
\foreach \n in {1,...,5} {
\doit{\n}
}
Note that there is a \pgffor@atendforeach
, but that does have a purpose; it seems to finish up the operation of the remember
key option. You want the after hook.
--
in front of the others). Use thecount
option to see where in the list you are.\foreach \n [count=\ni] in {a,...,z} {$\n_\ni+$}
which causes an error in my test. Even the pgfmanual-example doesn’t work. I’m using TL2010 and i didn’t find updates for PGF today (\listfiles
: pgffor.sty 2010/03/23 v2.10 (rcs-revision 1.18) and pgfrcs.sty 2010/10/25 v2.10 (rcs-revision 1.24)). PS: Maybe you can post your comment as an answer, so I can vote for you ;-)