12

I need to create a macro to render lists with a variable number of arguments (1+), e.g. \mylist{1,2,3} should expand to $\tilde{1}$--$\tilde{2}$--$\tilde{3}$. I'm trying to use xparse and \SplitList, but I didn't find a way to tell when I'm processing the last token (where I don't need the separator --).

\NewDocumentCommand\mylist{>{\SplitList{,}}m}
{
  \ProcessList{#1}{\myitem}
}
\newcommand\myitem[1]{$\tilde{#1}$--}

This would expand \mylist{1} to $\tilde{1}$-- instead of the desired $\tilde{1}$.

13

Recognizing the first item is easier than the last.

There are many strategies for this.

  1. Use a conditional

    \documentclass{article}
    \usepackage{xparse}
    \NewDocumentCommand\mylist{>{\SplitList{,}}m}
    {%
      \ProcessList{#1}{\myitem}%
      \firstitemtrue
    }
    
    \newif\iffirstitem
    \firstitemtrue   
    \newcommand\myitem[1]{%
      \iffirstitem
        \firstitemfalse
      \else
        --%
      \fi
      $\tilde{#1}$}
    
    \begin{document}
    \mylist{a,b,c}
    \end{document}
    
  2. Redefine the macro at first usage; doing the processing in a group will revert \myitem to the initial meaning.

    \documentclass{article}
    \usepackage{xparse}
    \NewDocumentCommand\mylist{>{\SplitList{,}}m}
    {%
      {\ProcessList{#1}{\myitem}}%
    }
    
    \newcommand\myitem[1]{$\tilde{#1}$\let\myitem\myitema}
    \newcommand\myitema[1]{--$\tilde{#1}$}
    
    \begin{document}
    \mylist{a,b,c}
    \end{document}
    
  3. Use a different approach with expl3 macros, which is more flexible at the expense of some complication.

    \documentclass{article}
    \usepackage{xparse}
    \ExplSyntaxOn
    \NewDocumentCommand\mylist{m}
     {
      \egreg_process_list:n {#1}
     }
    % define a sequence for storing the "massaged" items
    \seq_new:N \l_egreg_items_seq
    \cs_new_protected:Npn \egreg_process_list:n #1
     {
      % clear the sequence
      \seq_clear:N \l_egreg_items_seq
      % cycle through the arguments, storing "\tilde{<arg>}" in the sequence
      \clist_map_inline:nn { #1 }
       {
        \seq_put_right:Nn \l_egreg_items_seq { $\tilde{##1}$ }
       }
      % output the sequence putting "--" in between elements
      \seq_use:Nnnn \l_egreg_items_seq { -- } { -- } { -- }
     }
    \ExplSyntaxOff
    
    \begin{document}
    \mylist{a,b,c}
    \end{document}
    

The output in all three cases is

enter image description here

Note that you still need protecting end of lines with % in the body of \NewDocumentCommand unless you're in an \ExplSyntaxOn context.

|improve this answer|||||
  • An alternative to the \clist_map_inline:nn construction is to store the sequence with \seq_set_split:Nnn <seq> { , } (stable, doesn't ignore blank entries) or \seq_set_from_clist:Nn <seq> (experimental, ignores empty/blank entries), then using \seq_set_map:NNn <seq> <seq> { \exp_not:n {$\tilde{##1}$} } (experimental function), then \seq_use:Nnnn as you did. It is more efficient :-), and (perhaps) clearer. – Bruno Le Floch May 22 '13 at 9:49
4

I have used this trick often (see Cunning (La)TeX tricks). The approach is to define a list separator using a "delay". That is, define it as a definition so that the first use just defines itself:

enter image description here

\documentclass{article}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\NewDocumentCommand\mylist{O{--} >{\SplitList{,}}m}
{%
  \def\itemdelim{\def\itemdelim{#1}}% Define list separator with one delay
  \ProcessList{#2}{\myitem}% Process list
}
\newcommand\myitem[1]{\itemdelim$\tilde{#1}$}

\begin{document}
\mylist{a,b,c}
\end{document}

The additional optional argument to \mylist allows you to modify the list separator (or item delimiter) of the output. It defaults to --.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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