3

Suppose I want to address the same letter to 10 persons. The letters should be the same, except of course for the recipient's name and address.

Moreover, I want to enclose the name of all the other persons to whom I sent this letter.

I know I can combine multiple toggle using etoolbox, but isn't there a simpler way to go?

\documentclass{article}

\usepackage{etoolbox}

\newtoggle{A1}
\newtoggle{A2}
\newtoggle{A3}
% Etc.
\newtoggle{A10}

\toggletrue{A1}

\togglefalse{A2}
\togglefalse{A3}
%Etc.
\togglefalse{A10}

\iftoggle{A1}{
    \def\name{Toto}
    \def\adress{That Street}
    }
    {\iftoggle{A2}{
        \def\name{Tata}
        \def\adress{This Street}
    }
            {\iftoggle{A3}{
            %Etc.
            }
        }
    }

\begin{document}

Dear \name, 

please find below the name of the other recipients:
\begin{itemize}
\item Tata,
% Print the name of A2 -> A10 in that case.
\item Titi
\end{itemize}
\end{document}

I don't mind having to compile 10 times my document with just a slightly change, but I am not opposed neither to some scripting.

  • I think, this should rather be done with a list – user31729 Mar 8 '15 at 21:09
  • I agree, but how can a list be handled with LaTeX? – Clément Mar 8 '15 at 21:10
4

Every new recipient is inserted in a sequence that will serve as a basis for the mapping; the name and the address will be put in a property list.

The text of the letter is given as argument to \printletter that cycles over the items in the sequence; inside the letter, \name and \address will expand to the current recipient's, while \cc will print an itemized list of all other recipients' names.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\newrecipient}{mm}
 {% #1 = name, #2 = address
  \clement_new_recipient:nn { #1 } { #2 }
 }

\NewDocumentCommand{\name}{}
 {
  \prop_item:Nf \g_clement_recipients_prop { \l_clement_current_recipient_tl @ name }
 }

\NewDocumentCommand{\address}{}
 {
  \prop_item:Nf \g_clement_recipients_prop { \l_clement_current_recipient_tl @ address }
 }

\NewDocumentCommand{\cc}{}
 {
  \clement_cc_list:
 }

\NewDocumentCommand{\printletter}{+m}
 {
  \seq_map_inline:Nn \g_clement_recipients_seq
   {
    \tl_set:Nn \l_clement_current_recipient_tl { ##1 }
    #1
    \clearpage
   }
 }

\seq_new:N \g_clement_recipients_seq
\prop_new:N \g_clement_recipients_prop
\tl_new:N \l_clement_current_recipient_tl

\cs_generate_variant:Nn \prop_gput:Nnn { Nfn }
\cs_generate_variant:Nn \prop_item:Nn { Nf }
\cs_generate_variant:Nn \tl_if_eq:nnF { V }

\cs_new_protected:Npn \clement_new_recipient:nn #1 #2
 {
  \seq_gput_right:Nx \g_clement_recipients_seq { \tl_to_str:n { #1 } }
  \prop_gput:Nfn \g_clement_recipients_prop
   { \tl_to_str:n { #1 } @ name } { #1 }
  \prop_gput:Nfn \g_clement_recipients_prop
   { \tl_to_str:n { #1 } @ address } { #2 }
 }

\cs_new_protected:Npn \clement_cc_list:
 {
  \begin{itemize}
  \seq_map_inline:Nn \g_clement_recipients_seq
   {
    \tl_if_eq:VnF \l_clement_current_recipient_tl { ##1 }
     {
      \item \prop_item:Nf \g_clement_recipients_prop { ##1 @ name }
     }
   }
  \end{itemize}
 }

\ExplSyntaxOff

\newrecipient{Toto}{That Street\\Town}
\newrecipient{Tata}{This Street\\Village}
\newrecipient{T\'et\'e}{Another Place}

\begin{document}

\printletter{
  \hspace*{\fill}%
  \begin{tabular}{l@{}}
  \name \\
  \address
  \end{tabular}

\bigskip

Here, \today

\bigskip
\bigskip

Dear \name,\\
here is my letter to you and to other people that
you'll find listed at the bottom. Some other words
in order to fill some lines.

\bigskip

Sincerely yours

A. Uthor

\bigskip

\cc

}

\end{document}

Of course, the complex code will be stored in an external file to be \input, so it's reusable and it won't clobber the main document.

The shown printout uses a rule instead of the \clearpage in the code, so as to fill just a page.

enter image description here

  • The inevitable list facilities from expl3 ;-) – user31729 Mar 8 '15 at 21:55
  • @SoundsOfSilence Aren't they nice? – egreg Mar 8 '15 at 21:57
  • Still very cryptic to me ;-) – user31729 Mar 8 '15 at 21:58
  • They are indeed very nice. Both codes are still equally cryptic for me, but I guess that expl3 is somehow the future, so I should rather understand that code than yours, @SoundsOfSilence. I nonetheless took a careful look at it and thanks you for your nice solution and comments. – Clément Mar 8 '15 at 22:04
4

This uses the fact that it's possible to define \def macros and adding a delimiter for the arguments, say / slashes, separating name/address.

The \RegisterNames macro calls this splitting macro and stores the name and the address to separate lists, then uses an iterating command, producing the letter (excluding the current name in the list of recipients)

Edit

Improved version

\documentclass{article}

\usepackage{xstring}
\usepackage{etoolbox}

\def\nameaddresslist{}%
\def\namelist{}%
\def\addresslist{}%

% Helper macro
\makeatletter
\def\@splitmylist#1/#2\@nil{%
\listgadd{\namelist}{#1}%
\listgadd{\addresslist}{#2}%
\stepcounter{numnames}%
}


% Wrapper macro for actual splitting
\newcommand{\splitmylist}[1]{\@splitmylist#1\@nil}
\makeatother


\newcounter{numnames}%
\newcounter{tempcounter}%
\newcounter{loopcounter}%

% Get the address of entry number #1 in list #2
\newcommand{\getaddress}[2]{%
  \begingroup % Important, since \do is redefined
  \setcounter{tempcounter}{0}%
  \renewcommand*{\do}[1]{%
    \stepcounter{tempcounter}%
    \ifnumequal{\value{tempcounter}}{#1}{%
      ##1\listbreak%
    }{%
    }%
  }%
  \dolistloop{#2}%
  \endgroup
}

\newcommand{\iteratenames}[2]{%
\setcounter{loopcounter}{0}
Dear #2, 

please find below the name and address of the other recipients:
\begin{itemize}
\renewcommand*{\do}[1]{%
  \stepcounter{loopcounter}
  \IfStrEq{#2}{##1}{%
    }{%  Printing the other names and their address
    \item ##1 (\getaddress{\value{loopcounter}}{\addresslist})%
    }%
}%
\dolistloop{#1}%
\end{itemize}

% Only for demo purposes
\vskip\baselineskip
\hrule
\vskip\baselineskip


}


\newcommand{\RegisterNames}[1]{%
\forcsvlist{\splitmylist}{#1}
}

\begin{document}
\RegisterNames{Gandalf/{Gondor, Palace},Arwen/Rivendel,Frodo/Shire,Sauron/Mordor,Thorin/Erebor,Balin/Moria}

% Show list
\forlistloop{\iteratenames{\namelist}}{\namelist} % Could be packed into a command too
\end{document}

enter image description here

  • 1
    You've been much more inspired than I was for the name of the recipient! – Clément Mar 8 '15 at 21:40

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.