Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Is there a way for handling the last item in a \foreach-list in a special way. An example might illustrate an application for that:

\documentclass{minimal}
\usepackage{pgffor}
\begin{document}
\verb|\foreach \n in {1,...,5}{\n --}| leads to
\foreach \n in {1,...,5}{\n --} better would be
1--2--3--4--5 without the last --

A bad workaround: \foreach \n/\l in {1/--,2/--,3/--,4/--,5/{}}{\n\l}
or \foreach \n in {1--,2--,3--,4--,5}{\n}

% unfortunatly
% \foreach \n/\l in {1/--,...,4/--,5/{}}{\n\l}
% or \foreach \n in {1--,...,4--,5}{\n}
% doesn't work
\end{document}
share|improve this question
1  
It is often easier to test for the first element (and print -- in front of the others). Use the count option to see where in the list you are. –  Caramdir Apr 20 '11 at 3:27
    
@Caramdir: Your suggestion promises to be more general. –  Dmitrii Volosnykh Apr 20 '11 at 3:51
    
@Cardamdir: Good idea but it doesn’t seem to work: Could you try \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 ;-) –  Tobi Apr 20 '11 at 10:06

4 Answers 4

up vote 7 down vote accepted

Using the count option of \foreach, one can get a counter that stores the position in the list. Since the number of elements in the list might be unknown, it is usually easier to check for the first element instead of the last. Here is an example. (Note that in v2.10, tho count option does not work when only including pgffor, as it is missing \pgfmathparse. So you need to include pgfmath as well (which then complained about missing pgfkeys, so I just included everything in the example).)

\documentclass{minimal}
\usepackage{pgf,pgffor}

\begin{document}
\foreach \n [count=\ni] in {a,...,e} {% Comment signs at end of line to avoid
    \ifnum\ni=1%                        unwanted whitespace.
        \n%
    \else%
        --\n%
    \fi%
}
\end{document}

Alternatively, you could simply write

a%
\foreach \n in {b,...,e} {--\n}
share|improve this answer
    
Thank you! I wonder why this isn’t mentioned in the manual … –  Tobi Apr 22 '11 at 21:03

Subsection The dots notation of Section 56. Repeating Things: The Foreach Statement of pgfmanual v2.10 (pp.504--505) has a vast variety of examples. Among them one that allows you to do the following:

\documentclass{minimal}
\usepackage{pgffor}
\begin{document}
\foreach \n in {1--, ...--, 4--, 5}{\n}
\end{document}
share|improve this answer
1  
or 1\foreach \n in {--2,--...,--5}{\n} –  Alain Matthes Jun 14 '12 at 13:37

Although the other answers here provide solutions to accomplish the task at hand, they don't really address the requirements in the title of the question. I came across this question when working a solution to another question, but was disappointment that there was no solution here showing how to do special processing for the last member of a list. Hence am including it here in case someone else really needs it. And perhaps someone with a more elegant solution will be encouraged to post one.

I have to admit it is not very elegant, but just brute force approach to count the number of members at the beginning of the list processing, and keep a count to see which list member we are at. This allows one to apply different formatting for the first, middle, and last list member. So with \ColorListMembers{first,second,third,fourth} I can obtain:

enter image description here

Notes:

  • I am using the xstring package for the numerical comparison as I prefer it's syntax, but this could easily be adapted to not require that package.

References:

Code:

\documentclass[border=2pt]{standalone}
\usepackage{xcolor}
\usepackage{pgffor}
\usepackage{xstring}


% Specify the formatting of each of the list members
\newcommand*{\FormatFirstListMember}[1]{\textcolor{magenta}{\texttt{#1}}}%
\newcommand*{\FormatMiddleListMember}[1]{\textcolor{blue}{\texttt{#1}}}%
\newcommand*{\FormatLastListMember}[1]{\texttt{#1}}%


\newcounter{TotalNumberOfListMembers}%
\newcommand{\SetTotalNumberOfListMembers}[1]{%
    \setcounter{TotalNumberOfListMembers}{0}%
    \foreach \member in {#1} {%
        \stepcounter{TotalNumberOfListMembers}%
    }%
}%


\newcounter{CurrentListMemberCount}%
\newcommand*{\ColorListMembers}[1]{%
    \SetTotalNumberOfListMembers{#1}%
    \setcounter{CurrentListMemberCount}{0}%
    \foreach \member in {#1} {%
        \stepcounter{CurrentListMemberCount}%
        \IfEq{\the\value{CurrentListMemberCount}}{1}{%
            \FormatFirstListMember{\member}%
        }{%
            \IfEq{\the\value{CurrentListMemberCount}}{\the\value{TotalNumberOfListMembers}}{%
                --\FormatLastListMember{\member}%
            }{%
                --\FormatMiddleListMember{\member}%
            }%
        }%
    }%
}%

\begin{document}
    \ColorListMembers{first,second,third,fourth}
\end{document}
share|improve this answer

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.

share|improve this answer
    
There is no evil in that trick: it's age-old, age-long Carlisle wand. Even now he's fond of it. –  Ahmed Musa Jun 17 '12 at 8:01
    
Nice idea. Thanks :-) –  Tobi Jun 17 '12 at 13:14
    
Now if there just an \AtEndForeach{\finalize} hook, this would be perfect. –  Peter Grill Jun 17 '12 at 18:19
    
@Peter: Now there is :) –  Ryan Reich Jun 17 '12 at 18:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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