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 simple way of handling the first and/or the last item in an etoolbox-based list in a special way? Here’s a simple example:

\documentclass{article}

\usepackage{etoolbox}

\begin{document}

\forcsvlist{\listadd\namelist}{Tom, Dick, Harry, Jack}

\renewcommand*{\do}[1]{; #1}
\dolistloop{\namelist}

\renewcommand*{\do}[1]{#1, }
\dolistloop{\namelist}

\end{document}

The output is

; Tom; Dick; Harry; Jack

Tom, Dick, Harry, Jack,

How would I go about changing the above code to create the output

Tom; Dick; Harry; Jack

Tom, Dick, Harry and Jack

The first output would be easy to achieve if one could define the first item’s formatting to be simply #1 while the rest are formatted as ; #1. The second output would be easy to achieve if one could define all items to be formatted as , #1 except the first one, which should be #1 and the last one, which should be and #1.

Note that I’m looking for a solution for etoolbox lists, not other list structures.

share|improve this question

2 Answers 2

up vote 5 down vote accepted

For the first problem, I'd define \do to precede the entry with \process, whose initial meaning is just to redefine itself to the desired separator:

\newcommand{\semicolonlist}[1]{%
  \def\process{\def\process{; }}%
  \def\do##1{\process##1}%
  \dolistloop{#1}}

\semicolonlist\namelist

For the second problem, one can process the list once to get the number of elements and then use this information in a second pass:

\newcommand{\commaorandlist}[1]{%
  \count255=0
  \def\do##1{\advance\count255 1 \chardef\finalitem=\count255 }%
  \dolistloop{#1}%
  \count255=0
  \def\do##1{\advance\count255 1
    \ifnum\count255=\finalitem
      \space and\space
    \else
      \ifnum\count255=1
      \else
    ,\space
      \fi
    \fi##1}
  \dolistloop{#1}}

\commaorandlist\namelist    

These commands print the list; if you need to use them in an expandable context you can do, say for \commaorandlist,

\newcommand{\xcommaorandlist}[2]{%
  \count255=0
  \def\do##1{\advance\count255 1 \chardef\finalitem=\count255 }%
  \dolistloop{#1}%
  \count255=0
  \toks0={}% 
  \def\do##1{\advance\count255 1
    \edef\next{%
      \ifnum\count255=\finalitem
    \space and\space
      \else
        \ifnum\count255=1
        \else
          ,\space
        \fi
      \fi
    }
    \toks2={##1}%

    \edef\next{\the\toks0 \next \the\toks2}%
    \toks0=\expandafter{\next}%
  }%
  \dolistloop{#1}%
  \edef#2{\the\toks0 }%
}

and then call

\xcommaorandlist\namelist\finallist
\hypersetup{pdfauthor={\finallist}}
share|improve this answer
    
Thanks. It seems to work perfectly. This might really be a new question, but is there an easy way to also define the result as a fully expanded macro? I’m trying to use it to set the pdfauthor in \hypersetup, which doesn’t work. –  Karl Ove Hufthammer Nov 7 '11 at 20:48
    
@KarlOveHufthammer See edited answer –  egreg Nov 7 '11 at 21:06
    
Wow! That looks complicated, but works perfectly. Thanks! I’m currently reading the TeXbook and TeX by Topic, hoping to some day being able to understand that code. :) –  Karl Ove Hufthammer Nov 7 '11 at 21:24

here a simple solution which also counts the lists and the counter is used to locate the last element inside the list:

\documentclass{article}

\usepackage{etoolbox}

\begin{document}
\newcounter{elementcount}
\forcsvlist{\stepcounter{elementcount}\listadd\namelist}{Tom, Dick, Harry, Jack}

\number\value{elementcount}:
\def\do#1{%
 \ifnumequal{\value{elementcount}}{1}{%
  #1}{\addtocounter{elementcount}{-1}#1,~}%   
}
\dolistloop{\namelist}

\end{document}
share|improve this answer
    
I accepted egreg’s answer, but I also like this one very much, as it’s easy to see how to modify it to handle special-casing of different items than the first or last one. –  Karl Ove Hufthammer Nov 7 '11 at 20:51

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.