Use loop for creating defined number of newcommands counting authors

expansionfor loopforeachloopsvariable

For my template I want to create possibility to define a number of authors and automatically create a respective number of variables/commands which save the name of any author and make it able to print them later. The code has to be in the preamble.

For creating different variables/commands of the kind \varname{...} which can be printed with \printvarname, I, rather randomly, found the following code here on tex.SE which works fine:

\makealetter
\newcommand{\NewVariable}[1]{%
    \expandafter\newcommand\csname #1\endcsname[1]{\@namedef{@#1}{##1}}
    \@namedef{@#1}{}
    \expandafter\newcommand\csname print#1\endcsname{%
        \ifthenelse{\equal{\csname @#1\endcsname}{}}{}{\csname @#1\endcsname}}
}
\makeatother

Now I want to create a loop which automatically creates a predefined number of these commands of the syntax \authorone, \authortwo etc. For the definition of the numbers of authors I use a simple command: \newcommand{\setauthors}[1]{\def\numauthors{#1}}. One problem seems to be that a commandname can't take integers, but i need integers to define the number of authors. So i use the fmtcount package to convert them into words.

I tried different approaches from this website (foreach, @for, xintFor), but couldn't get one to work properly.

Here is a MWE with some approaches. I commented my test loops and added a simple example how it should be used:

\documentclass[%
]{article}
\usepackage[T1]{fontenc}

\usepackage{ifthen}
\makeatletter % command to set multiple persistent variables with content
\newcommand{\NewVariable}[1]{%
    \expandafter\newcommand\csname #1\endcsname[1]{\@namedef{@#1}{##1}}
    \@namedef{@#1}{}
    \expandafter\newcommand\csname print#1\endcsname{%
        \ifthenelse{\equal{\csname @#1\endcsname}{}}{}{\csname @#1\endcsname}}
}
\makeatother 

\usepackage{pgffor}
\usepackage{fmtcount} % to convert integers in words: e.g. 1 into one
\usepackage{xinttools}

\newcommand{\setauthors}[1]{\def\numauthors{#1}}

\setauthors{3} %set number of authors

%\foreach \x in {1,...,\numauthors}{%
%       \NewVariable{author\numberstringnum{\x}}
%       }

%\xintFor #1 in {\xintSeq{1}{\numauthors}} \do {\NewVariable{author\numberstringnum{#1}}}
% also tried the starred version \xintFor*

%\makeatletter % I know the definition of a range from 1 to \numauthors is not correct, its just a placeholder
%\@for\authorcount:1,...,\numauthors\do{\NewVariable{author\numberstringnum{\authorcount}}}
%\makeatother

\NewVariable{authorone} % example for defined variable/command and how it should work

\authorone{Jimmy Buckets}

\begin{document}

\printauthorone

\end{document}

There seem to be much more variants of loops from other packages (also expl3 versions, which I understand even less), but I would prefer a solution with a minimum on required extra packages. Nevertheless, in the end it's important that it works. The future user should only add a number to \setauthors and fill out the generated author variables. All other stuff should be automated. It may also be an option to asign the authornumber to an array first…

I guess it's an expansion problem of the nested commands (NewVariable, numberstring..., loop). Unfortunately, the expansion sequence/order still remains a sealed book for me, because it differs so much from most programming languages I'm (a little bit) used to.

EDIT

To use @Alans great answer including the orcid. The expl3 command \cs_new_protected:Nn \l_lukeflo_get_orcid:n for creating a valid Orcid works better using a pre-defined command for getting the Orcid link including the symbol:

\usepackage{orcidlink}
\newcommand{\orcidid}[1]{\orcidlink{#1}\space\href{https://orcid.org/#1}{#1}}
...
\cs_new_protected:Nn \l_lukeflo_get_orcid:n {
    \tl_set:Nx \l_tmpa_tl {\seq_item:Nn \l_lukeflo_orcid_seq {#1}}
    \orcidid{\l_tmpa_tl}\par
}

Otherwise, href will add an unnecessary .pdf extension to the link. See my comments below Alans answer.

I am already grateful for your help

Best Answer

Your stated goal in the question and in comments is to reduce the complexity of the markup that the users of your package or class need to use. To my mind then, creating multiple different command names is very counterintuitive from a user's point of view. So here's an approach that achieves the same goal, but with maximally simple user syntax: commands to enter authors, affiliations, and emails as simple comma delimited lists, some formatting commands implemented with a key-value setup command (which may or may not need to be user facing) and a command to print the elements. I've used expl3 methods which are built into the LaTeX kernel, so there are no extra packages involved. This answer is intended to show the kind of thing that can be quite easily done with these methods.

In this example, the only user-facing commands that are required are the \authors, \affiliations, and \emails commands. The rest may or may not need to be user facing depending on your actual use case. Since authors often have multiple affiliations, they can be entered as a list surrounded by braces. I've also added an \orcids command and shown code to produce the ORCID logo and link.

\documentclass{article}
\usepackage{orcidlink}
\ExplSyntaxOn
% First define three sequences for storing the data
\seq_new:N \l_lukeflo_authors_seq
\seq_new:N \l_lukeflo_email_seq
\seq_new:N \l_lukeflo_affil_seq
\seq_new:N \l_lukeflo_orcid_seq 
% Now set up some keys for modifying the output if needed
\keys_define:nn{mypackage}{
    author.tl_set:N = \l_lukeflo_authformat_tl,
    affil.tl_set:N = \l_lukeflo_affilformat_tl,
    email.tl_set:N = \l_lukeflo_emailformat_tl,
}
% User command to set the formatting keys.
\NewDocumentCommand{\authorSetup}{m}{
    \keys_set:nn {mypackage} {#1}}

% Set up the defaults
\authorSetup{author=\itshape,affil={},email=\ttfamily}

% User command to enter authors (comma separated)
\NewDocumentCommand{\authors}{m}{
    \seq_set_from_clist:Nn \l_lukeflo_authors_seq {#1}
}
% User command to enter affiliations (comma separated; multiple affiliations with {})
\NewDocumentCommand{\affiliations}{m}{
    \seq_set_from_clist:Nn \l_lukeflo_affil_seq {#1}
}
% User command to enter emails
\NewDocumentCommand{\emails}{m}{
    \seq_set_from_clist:Nn \l_lukeflo_email_seq {#1}
}
\NewDocumentCommand{\orcids}{m}{
    \seq_set_from_clist:Nn \l_lukeflo_orcid_seq {#1}
}
% internal command to map print affiliations
\cs_new_protected:Nn \lukeflo_get_affils:n {
    \clist_set:Nx \l_tmpa_clist {\seq_item:Nn \l_lukeflo_affil_seq {#1}}
    \clist_map_inline:Nn \l_tmpa_clist {\l_lukeflo_affilformat_tl {##1}\par}
}
\cs_new_protected:Nn \lukeflo_get_orcid:n {
    \tl_set:Nx \l_tmpa_tl {\seq_item:Nn \l_lukeflo_orcid_seq {#1}}
    \orcidlink{\l_tmpa_tl}\space\l_lukeflo_emailformat_tl
    \href{https\c_colon_str//orcid.org/\l_tmpa_tl/}{\l_tmpa_tl}\par
}

% internal command to print an author/affiliations/email block
\cs_new_protected:Nn \lukeflo_map_author_info:nn {
    {\parindent=0pt
    {\l_lukeflo_authformat_tl\seq_item:Nn \l_lukeflo_authors_seq {#1}\par}
    {\lukeflo_get_affils:n {#1}}
    {\l_lukeflo_emailformat_tl\seq_item:Nn \l_lukeflo_email_seq {#1}\par}
    {\lukeflo_get_orcid:n {#1}}
    \vspace{\baselineskip}
    }
}
% User command to print all the author blocks
\NewDocumentCommand \printauthors {} {
    \seq_map_indexed_function:NN \l_lukeflo_authors_seq \lukeflo_map_author_info:nn
}
\ExplSyntaxOff
\authors{Margaret Atwood, Zadie Smith, Madeleine Thien}
\affiliations{University of Toronto,{New York University,Columbia University},Brooklyn College}
\emails{[email protected], [email protected],[email protected]}
\orcids{0000-0000-0000-0000,0000-0000-0000-0000,0000-0000-0000-0000}

\begin{document}
\printauthors
\authorSetup{author=\bfseries}
\printauthors
\end{document}

output of code

Related Question