7

I was wondering if there are any clever workaround for including a number in a custom macro name?

I'm working with a platform that integrates LaTeX with a computer algebra system, and frequently have variables such as a[1], a[2] etc that I have to assign to tex commands.

Right now, the most functional solution I've found is using Roman numerals e.g. \newcommand{\ai}{a[1]}; however, for various reasons, it's not ideal.

I was trying to think of some way I could use an argument to distinguish them (e.g. \a{1}, \a{2} etc); however, due to further limitations, I'd have to be able to specify the exact output for different arguments. Is it possible to define a custom macro whose output is different for different inputs? e.g.

\a{1} |--> foo
\a{2} |--> bar
\a{3} |--> baz
9

I'm not sure if this solution applies to your needs, since your examples are not precise enough but the listofitems package seems to do the job:

\documentclass{article}
\usepackage{listofitems}

\begin{document}
    \readlist\f{foo,bar,baz}
    Now f[1] is \f[1] and f[3] is \f[3].
\end{document}

read elements from a list

6

well you shouldn't use \a that is already defined. But beside from this, naturally commands can do different things depending on the argument.

If you know your arguments are numbers, you could e.g. get the content from a sequence:

\documentclass{article}

\ExplSyntaxOn
\seq_new:N\l_rax_data_seq
\seq_set_from_clist:Nn \l_rax_data_seq {foo,bar,baz}
\NewDocumentCommand\rax{m}
 {
   \seq_item:Nn \l_rax_data_seq {#1}   
 }
\ExplSyntaxOff

\begin{document}

\rax{1}, \rax{2}, \rax{3}

\end{document}

enter image description here

6

While this sort of mimics the listofitems usage syntax, it allows a different form of input other than a simple list, which can be non-sequential if desired.

\documentclass{article}
\makeatletter
\newcommand\setaside[1]{%
  \def#1[##1]{%
    \csname\expandafter\@gobble\string#1[##1]\endcsname}}
\def\define#1[#2]#3{%
  \expandafter\def\csname\expandafter
  \@gobble\string#1[#2]\endcsname{#3}}
\makeatother
\begin{document}
\setaside\a
\define\a[1]{foo}
\define\a[3]{baz}
\define\a[2]{bar}
\define\a[7]{barr}

Now, a[1] is \a[1] and a[3] is \a[3].
\end{document}

enter image description here

0
6

Ad question 1:

I was wondering if there are any clever workaround for including a number in a custom macro name?

I'm working with a platform that integrates LaTeX with a computer algebra system, and frequently have variables such as a[1], a[2] etc that I have to assign to tex commands.

Right now, the most functional solution I've found is using Roman numerals e.g. \newcommand{\ai}{a[1]}; however, for various reasons, it's not ideal.

As under normal category code régime you cannot obtain control-word-tokens \a1, \a2, etc, or \a[1], \a[2], etc directly by having TeX read and tokenize .tex-input and as correct invocation of \csname..\endcsname in combination with \expandafter sometimes seems cumbersome, I offer a macro \CsNameToCsToken which can be used for creating, e.g., the control-word-token \a1 from the character-token-sequence a1 or the control-word-token \a2 from the character-token-sequence a2, etc, or the control-word-token \a[1] from the character-token-sequence a[1] or the control-word-token \a[2] from the character-token-sequence a[2], etc.

Syntax:

\CsNameToCsToken⟨stuff not in braces⟩{⟨NameOfCs⟩}

⟨stuff not in braces⟩\NameOfCs

(⟨stuff not in braces⟩ may be empty.)

(Due to \romannumeral-expansion the result is obtained by triggering two expansion-steps, e.g., by having two "hits" with \expandafter.)

With such a macro you are not bound to specific definition commands:

\CsNameToCsToken{foo}\foo  .

\CsNameToCsToken\newcommand{foo}\newcommand\foo  .

\CsNameToCsToken\DeclareRobustCommand{foo}\DeclareRobustCommand\foo  .

\CsNameToCsToken\global\long\outer\def{foo}\global\long\outer\def\foo  .

\CsNameToCsToken\expandafter{foo}\bar\expandafter\foo\bar  .

\CsNameToCsToken\let{foo}=\bar\let\foo=\bar  .

\CsNameToCsToken\CsNameToCsToken\let{foo}={bar}\CsNameToCsToken\let\foo={bar}\let\foo=\bar  .

\CsNameToCsToken\string{foo}\string\foo  .

\CsNameToCsToken\meaning{foo}\meaning\foo  .

\CsNameToCsToken\NewDocumentCommand{foo}...\NewDocumentCommand\foo...  .

\makeatletter
%%===============================================================================
%% End \romannumeral-driven expansion safely:
%%===============================================================================
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%===============================================================================
%% Obtain control sequence token from name of control sequence token:
%%===============================================================================
%% \CsNameToCsToken<stuff not in braces>{NameOfCs}
%% ->  <stuff not in braces>\NameOfCs
%% (<stuff not in braces> may be empty.)
\@ifdefinable\CsNameToCsToken{%
  \long\def\CsNameToCsToken#1#{\romannumeral\InnerCsNameToCsToken{#1}}%
}%
\newcommand\InnerCsNameToCsToken[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{\UD@stopromannumeral#1}%
}%
\newcommand\UD@exchange[2]{#2#1}%
\makeatother

\documentclass{article}

\begin{document}

\begin{verbatim}
Define \A[1]:
\CsNameToCsToken\newcommand*{A[1]}{%
  This is the replacement-text of the command whose name is \texttt{A[1]}.%
}
\end{verbatim}

\CsNameToCsToken\newcommand*{A[1]}{%
  This is the replacement-text of the command whose name is \texttt{A[1]}.%
}

\begin{verbatim}
Define \A[2]:
\CsNameToCsToken\newcommand*{A[2]}{%
  This is the replacement-text of the command whose name is \texttt{A[2]}.%
}
\end{verbatim}

\CsNameToCsToken\newcommand*{A[2]}{%
  This is the replacement-text of the command whose name is \texttt{A[2]}.%
}

\begin{verbatim}
Using \A[1]: \CsNameToCsToken{A[1]}
\end{verbatim}
\CsNameToCsToken{A[1]}

\begin{verbatim}
Using \A[2]: \CsNameToCsToken{A[2]}
\end{verbatim}
\CsNameToCsToken{A[2]}


\end{document}

enter image description here

Ad question 2:

Is it possible to define a custom macro whose output is different for different inputs?

There are many more possibilities of how varying output/forking can be done depending on the tokens that make up a macro argument. I list six of them.

Possibility 1: See, e.g., the \ref-command. Its output varies depending on the input/argument. Using the package zref you can define your own class of referencing-labels which are used for assigning a value to a named constant and your own class of referencing-commands for retrieving these values. Advantage: Within the second compilation with LaTeX all variables' values are available throughout the entire compilation, not just from the moment on when they were defiined. Disadvantage: You need at least two LaTeX-runs for things to match out.

\errorcontextlines=10000
\RequirePackage{xparse}
\documentclass{article}
\usepackage{zref}

\makeatletter

\@ifdefinable\@zrefpropdefined{%
  \ZREF@Robust\def\@zrefpropdefined{%
    \zref@wrapper@babel\@ZREFpropdefined
  }%
}%
\@ifdefinable\@ZREFpropdefined{%
  \def\@ZREFpropdefined#1#2#3#4{%
    % #1  - label
    % #2  - property
    % #3  - tokens in case label and property are available
    % #4  - tokens in case label undefined or property not available
    \zref@ifrefundefined{#1}{%
       \zref@refused{#1}#4%
    }{%
      \zref@ifrefcontainsprop{#1}{#2}{#3}{%
        \protect\G@refundefinedtrue
        \@latex@warning{%
           Missing property `#2' in reference `#1' on page \thepage
        }%
        #4%
      }%
    }%
  }%
}%

\zref@newprop{ValueOfVariable}{\nfss@text{\reset@font\bfseries??}}%
\NewDocumentCommand\IntroduceNewVariable{mm}{%
  \@bsphack
  \zref@wrapper@immediate{%
    \zref@setcurrent{ValueOfVariable}{#2}%
    \zref@labelbyprops{#1}{ValueOfVariable}%
  }%
  \@esphack
}%
\NewDocumentCommand\RetrieveValueOfVariable{m}{%
  \zref@extractdefault{#1}{ValueOfVariable}{%
    \@zrefpropdefined{#1}{ValueOfVariable}{%
      \protect\G@refundefinedtrue
      \@latex@warning{%
        Unspecified problem/error related to reference `#1' on page \thepage
      }%
    }{}%
    \nfss@text{\reset@font\bfseries??}%
  }%
}%
\makeatother

\begin{document}

Retrieving the value of Variable \texttt{A[1]} yields:
\RetrieveValueOfVariable{A[1]}

Retrieving the value of Variable \texttt{A[2]} yields:
\RetrieveValueOfVariable{A[2]}


\IntroduceNewVariable{A[1]}{Value of variable \texttt{A[1]}.}%

Some Text

\IntroduceNewVariable{A[2]}{Value of variable \texttt{A[2]}.}%

Retrieving the value of Variable \texttt{A[1]} yields:
\RetrieveValueOfVariable{A[1]}

Retrieving the value of Variable \texttt{A[2]} yields:
\RetrieveValueOfVariable{A[2]}

\end{document}

enter image description here

Possibility 2: If you don't mind coping with the oddities of the package pgfkeys, which is a component of TikZ/pgf, you can implement an interface for parsing a comma-list where

  • items without = denote names of variables whose values are to be retrieved and
  • items with = denote assigning the variable whose name is at the left of = a value consisting of the tokens at the right of the =.

PutTokens is a special key: It does denote neither variable-assignment, nor retrieval of variables. The tokens forming its value are just placed into the token-queue.

Be aware that pgfkeys removes spaces that surround key and/or value no matter if key/value is between braces. (Braces might be needed for masking commas that shall not separate elements of the comma-list but shall be part of values or the names of keys. Braces might be needed for masking = that shall not separate keys from values but shall be part of values or the names of keys.)

%\errorcontextlines=10000
\documentclass{article}
\usepackage{pgfkeys}
\makeatletter
\newcommand\ValueOfUndefinedVariable[1]{%
  \GenericError{\space\@spaces\@spaces}{%
    Error: Variable `#1` undefined\on@line
  }{}{%
   \string\Variable{<variable's name>=<tokens denoting variable's value>}%
   \MessageBreak defines variables.%
  }%
  \nfss@text{\reset@font\bfseries??}%
}%
\@ifdefinable\@gobbletopgfkeysnovalue{%
  \long\def\@gobbletopgfkeysnovalue#1\pgfkeysnovalue{}%
}%
\@ifdefinable\@keeptopgfkeysnovalue{%
  \long\def\@keeptopgfkeysnovalue#1\pgfkeysnovalue{#1}%
}%
\newcommand\CheckWhetherPgfkeysnovalue[1]{%
  \ifcat$\detokenize\expandafter{\@gobbletopgfkeysnovalue#1\pgfkeysnovalue}$%
  \expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
  {%
    \ifcat$\detokenize\expandafter\expandafter\expandafter{%
      \@keeptopgfkeysnovalue\@firstofone{}#1%
     }$%
     \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  }{\@secondoftwo}%
}%
\makeatother

\newcommand\MyVariablesHandle[2]{%
  % #1 name of variable
  % #2 value of variable
  \CheckWhetherPgfkeysnovalue{#2}{%
    \pgfkeys{/MyVariables/#1/.initial={\ValueOfUndefinedVariable{#1}},
             /MyVariables/#1%
            }%
  }{%
    \pgfkeys{/MyVariables/#1/.initial={#2}}%
  }%
}%
\pgfkeys{%
  /MyVariables/.unknown/.code={%
     \expandafter\MyVariablesHandle\expandafter{\pgfkeyscurrentname}{#1}%
  },
  /MyVariables/PutTokens/.code={#1},
  /MyVariables/PutTokens/.value required,
}%


\newcommand\Variables[1]{\pgfkeys{/MyVariables/.cd,#1}}

\begin{document}

% Define variables A[1] and A[2]
\Variables{%
 A[1]={Value of variable \texttt{A[1]}},
 A[2]={Value of variable \texttt{A[2]}},
}%

\Variables{%
 % Deliver values of variables A[1] and A[2]
 PutTokens={\noindent Retrieving the value of Variable \texttt{A[1]} yields:\space },
 A[1],
 PutTokens={.\\Retrieving the value of Variable \texttt{A[2]} yields:\space },
 A[2],
 % Define variables A[3] and A[4]
 A[3]={Value of variable \texttt{A[3]}},
 A[4]={Value of variable \texttt{A[4]}},
 % Deliver values of A[3] and A[4]
 PutTokens={.\\Retrieving the value of Variable \texttt{A[3]} yields:\space },
 A[3],
 PutTokens={.\\Retrieving the value of Variable \texttt{A[4]} yields:\space },
 A[4],
 PutTokens={.},
}%

\bigskip
% Deliver values of variables A[1] and A[2] and [A3] and [A4]

\Variables{%
 % Print variables A[1] and A[2] and [A3] and [A4]
 PutTokens={\noindent Retrieving the value of Variable \texttt{A[1]} yields:\space },
 A[1],
 PutTokens={.\\Retrieving the value of Variable \texttt{A[2]} yields:\space },
 A[2],
 PutTokens={.\\Retrieving the value of Variable \texttt{A[3]} yields:\space },
 A[3],
 PutTokens={.\\Retrieving the value of Variable \texttt{A[4]} yields:\space },
 A[4],
 PutTokens={.},%
}%

\bigskip
% Deliver values of variables A[1] and A[2] and [A3] and [A4]

\noindent Retrieving the value of Variable \texttt{A[1]} yields: \Variables{A[1]}.
\\Retrieving the value of Variable \texttt{A[2]} yields: \Variables{A[2]}.
\\Retrieving the value of Variable \texttt{A[3]} yields: \Variables{A[3]}.
\\Retrieving the value of Variable \texttt{A[4]} yields: \Variables{A[4]}.

\end{document}

enter image description here

Possibility 3: You say you work with a platform that integrates LaTeX with a computer algebra system.

I don't know how the computer algebra system delivers the variables to LaTeX.
Probably an approach using a .csv-file and the package datatool might be of interest.

With the following approach a database-file variables.csv is created.

From that a database is created via \DTLloaddb.

That database is iterated each time the value of a vriable is to be retrieved. This is rather inefficient.

It is relied on NameOfVariable forming a primary key of the database.

\errorcontextlines=10000

%=====Let LaTeX create a .csv-file holding a database of names and ========
%     values of named constants.
%     This could as well be done via export to .csv-file by whatsoever
%     other program. 

\begin{filecontents*}{variables.csv}
PrimaryKey,NameOfVariable,ValueOfVariable
1,A[1],Value of variable \texttt{A[1]}.
2,A[2],Value of variable \texttt{A[2]}.
3,A[3],Value of variable \texttt{A[3]}.
4,A[4],Value of variable \texttt{A[4]}.
\end{filecontents*}

%==========================================================================

\documentclass{article}

\usepackage{datatool}% For loading and iterating databases; internally loads the package ifthen

\makeatletter
\newcommand\ValueOfUndefinedVariable[1]{%
  \GenericError{\space\@spaces\@spaces}{%
    Error: Variable `#1` undefined\on@line
  }{}{%
   \string\Variable{<variable's name>=<tokens denoting variable's value>}%
   \MessageBreak defines variables.%
  }%
  \nfss@text{\reset@font\bfseries??}%
}%
\newif\ifvariabledefined
\newcommand\RetrieveValueOfVariable[2]{%
  \global\variabledefinedfalse
  \DTLforeach*[{\equal{#1}{\NameOfVariable}}]{variables}{%
    \PrimaryKey=PrimaryKey,%
    \NameOfVariable=NameOfVariable,%
    \ValueOfVariable=ValueOfVariable%
  }{%
    \dtlbreak
    \global\variabledefinedtrue
    \ValueOfVariable
  }%
  \ifvariabledefined\expandafter\@gobble\else\expandafter\@firstofone\fi
  {#2}%
}%
\makeatother

\DTLloaddb{variables}{variables.csv}

\begin{document}

Retrieving the value of Variable \texttt{A[1]} yields:
\RetrieveValueOfVariable{A[1]}{\ValueOfUndefinedVariable{A[1]}}

Retrieving the value of Variable \texttt{A[2]} yields:
\RetrieveValueOfVariable{A[2]}{\ValueOfUndefinedVariable{A[2]}}

Retrieving the value of Variable \texttt{A[3]} yields:
\RetrieveValueOfVariable{A[3]}{\ValueOfUndefinedVariable{A[3]}}

Retrieving the value of Variable \texttt{A[4]} yields:
\RetrieveValueOfVariable{A[4]}{\ValueOfUndefinedVariable{A[4]}}

\end{document}

enter image description here

Of course you can combine this with \CsnameToCsToken for defining a macro for each variable.
This way you don't have to iterate the database each time when retrieving the value of a variable.

\errorcontextlines=10000

%=====Let LaTeX create a .csv-file holding a database of names and ========
%     values of named constants.
%     This could as well be done via export to .csv-file by whatsoever
%     other program. 

\begin{filecontents*}{variables.csv}
PrimaryKey,NameOfVariable,ValueOfVariable
1,A[1],Value of variable \texttt{A[1]}.
2,A[2],Value of variable \texttt{A[2]}.
3,A[3],Value of variable \texttt{A[3]}.
4,A[4],Value of variable \texttt{A[4]}.
\end{filecontents*}

%==========================================================================

\documentclass{article}

\usepackage{datatool}% For loading and iterating databases; internally loads 
                     % the package ifthen

\makeatletter
%%===============================================================================
%% End \romannumeral-driven expansion safely:
%%===============================================================================
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%===============================================================================
%% Obtain control sequence token from name of control sequence token:
%%===============================================================================
%% \CsNameToCsToken<stuff not in braces>{NameOfCs}
%% ->  <stuff not in braces>\NameOfCs
%% (<stuff not in braces> may be empty.)
\@ifdefinable\CsNameToCsToken{%
  \long\def\CsNameToCsToken#1#{\romannumeral\InnerCsNameToCsToken{#1}}%
}%
\newcommand\InnerCsNameToCsToken[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{\UD@stopromannumeral#1}%
}%
\newcommand\UD@exchange[2]{#2#1}%
%%===============================================================================
\newcommand\ValueOfUndefinedVariable[1]{%
  \GenericError{\space\@spaces\@spaces}{%
    Error: Variable `#1` undefined\on@line
  }{}{%
   \string\Variable{<variable's name>=<tokens denoting variable's value>}%
   \MessageBreak defines variables.%
  }%
  \nfss@text{\reset@font\bfseries??}%
}%
%%===============================================================================
\newcommand\RetrieveValueOfVariable[2]{%
  \@ifundefined{Variable@#1}{#2}{\CsNameToCsToken{Variable@#1}}%
}%
\makeatother

\DTLloaddb{variables}{variables.csv}

\DTLforeach*{variables}{%
  \PrimaryKey=PrimaryKey,%
  \NameOfVariable=NameOfVariable,%
  \ValueOfVariable=ValueOfVariable%
}{%
  \csname UD@exchange\expandafter\endcsname\expandafter{\expandafter{\ValueOfVariable}}{%
    \CsNameToCsToken\newcommand*{Variable@\NameOfVariable}%
  }%
  \CsNameToCsToken\CsNameToCsToken\global\let{Variable@\NameOfVariable}{Variable@\NameOfVariable}%
}%

\begin{document}

Retrieving the value of Variable \texttt{A[1]} yields:
\RetrieveValueOfVariable{A[1]}{\ValueOfUndefinedVariable{A[1]}}

Retrieving the value of Variable \texttt{A[2]} yields:
\RetrieveValueOfVariable{A[2]}{\ValueOfUndefinedVariable{A[2]}}

Retrieving the value of Variable \texttt{A[3]} yields:
\RetrieveValueOfVariable{A[3]}{\ValueOfUndefinedVariable{A[3]}}

Retrieving the value of Variable \texttt{A[4]} yields:
\RetrieveValueOfVariable{A[4]}{\ValueOfUndefinedVariable{A[4]}}

\end{document}

enter image description here

Possibility 4: You can use an expl3-property-list—properties are variables, values of properties are values of variables:

\errorcontextlines=10000
\documentclass{article}
\RequirePackage{xparse}
\ExplSyntaxOn
\prop_new:c  {Variables}
\NewDocumentCommand\RetrieveValueOfVariable{mm}{
  % #1 = Name of variable
  % #2 = tokens in case variable is not defined
  \prop_if_in:cnTF {Variables} {#1}
                   {  \prop_item:cn {Variables} {#1}   }
                   { #2 }
}
\NewDocumentCommand\SetVariables{m}{
  \keyval_parse:NNn \__MYSetvariable:n \__MYSetvariable:nn {#1}
}
\cs_new:Nn \__MYSetvariable:n {\__MYSetvariable:nn {#1}{}}
\cs_new:Nn \__MYSetvariable:nn {
  \prop_put:cnn {Variables} {#1} {#2}
}
\ExplSyntaxOff

\makeatletter
\NewDocumentCommand\ValueOfUndefinedVariable{}{\nfss@text{\reset@font\bfseries??}}%
\makeatother

\SetVariables{%
 A[1]={Value of variable \texttt{A[1]}.},
 A[2]={Value of variable \texttt{A[2]}.},
}%
\SetVariables{%
 A[3]={Value of variable \texttt{A[3]}.},
 A[4]={Value of variable \texttt{A[4]}.},
}%

\begin{document}

Retrieving the value of Variable \texttt{A[1]} yields:
\RetrieveValueOfVariable{A[1]}{\ValueOfUndefinedVariable}

Retrieving the value of Variable \texttt{A[2]} yields:
\RetrieveValueOfVariable{A[2]}{\ValueOfUndefinedVariable}

Retrieving the value of Variable \texttt{A[3]} yields:
\RetrieveValueOfVariable{A[3]}{\ValueOfUndefinedVariable}

Retrieving the value of Variable \texttt{A[4]} yields:
\RetrieveValueOfVariable{A[4]}{\ValueOfUndefinedVariable}

\end{document}

enter image description here

Possibility 5: Use delimited arguments for forking. This is cumbersome and of limited use and funny because you set the value of variables within the definition-text of the two macros used for retrieving the values:

\errorcontextlines=10000
\documentclass{article}
\makeatletter
\newcommand\ValueOfUndefinedVariable{\nfss@text{\reset@font\bfseries??}}%
\@ifdefinable\gobbletoexclam{\long\def\gobbletoexclam#1!{}}%
\newcommand\RetrieveValueOfVariable[2]{%
  \ifcat$\detokenize\expandafter{\gobbletoexclam#1!}$%
  \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {%
    \VariableSelectionFork
    !#1!A[2]!A[3]!A[4]!{Value of variable \texttt{A[1]}.}%
    !A[1]!#1!A[3]!A[4]!{Value of variable \texttt{A[2]}.}%
    !A[1]!A[2]!#1!A[4]!{Value of variable \texttt{A[3]}.}%
    !A[1]!A[2]!A[3]!#1!{Value of variable \texttt{A[4]}.}%
    !A[1]!A[2]!A[3]!A[4]!{#2}!!!!%
  }{#2}%
}%
\@ifdefinable\VariableSelectionFork{%
  \long\def\VariableSelectionFork#1!A[1]!A[2]!A[3]!A[4]!#2#3!!!!{#2}%
}%
\makeatother

\begin{document}

Retrieving the value of Variable \texttt{A[1]} yields:
\RetrieveValueOfVariable{A[1]}{\ValueOfUndefinedVariable}

Retrieving the value of Variable \texttt{A[2]} yields:
\RetrieveValueOfVariable{A[2]}{\ValueOfUndefinedVariable}

Retrieving the value of Variable \texttt{A[3]} yields:
\RetrieveValueOfVariable{A[3]}{\ValueOfUndefinedVariable}

Retrieving the value of Variable \texttt{A[4]} yields:
\RetrieveValueOfVariable{A[4]}{\ValueOfUndefinedVariable}

\end{document}

enter image description here

Possibility 6: In case the names of your variables denote a consecutive numbering, another approach could be extracting the k-th argument of a list of arguments whose elements denote the values of variables:

\errorcontextlines=10000
\documentclass{article}

\makeatletter
%% Code for \ExtractKthArg
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@Exchange,
%%    \UD@stopromannumeral, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
  \expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \ExtractKthArg{<integer K>}%
%%               {<tokens in case list of undelimited args doesn't have a k-th argumnent>}%
%%               {<list of undelimited args>} %
%% 
%% In case there is no K-th argument in <list of indelimited args> : 
%%   Does deliver <tokens in case list of undelimited args doesn't have a k-th argumnent.
%% In case there is a K-th argument in <list of indelimited args> : 
%%   Does deliver that K-th argument with one level of braces removed.
%%
%% Examples:
%%
%%   \ExtractKthArg{0}{not available}{ABCDE} yields: not available
%%
%%   \ExtractKthArg{3}{not available}{ABCDE} yields:  C
%%
%%   \ExtractKthArg{3}{not available}{AB{CD}E} yields:  CD
%%
%%   \ExtractKthArg{4}{not available}{{001}{002}{003}{004}{005}} yields: 004
%%
%%   \ExtractKthArg{6}{not available}{{001}{002}{003}} yields: not available 
%% 
%%=============================================================================
\newcommand\ExtractKthArg[2]{%
  \romannumeral%
  % #1: <integer number K>
  % #2: <action if there is no K-th argument>
  \expandafter\UD@ExtractKthArgCheck
  \expandafter{\romannumeral\number\number#1 000}{#2}%
}%
\newcommand\UD@ExtractKthArgCheck[3]{%
  \UD@CheckWhetherNull{#1}{\UD@stopromannumeral#2}{% empty
    \expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}{#2}{#3}%
  }%
}%
\begingroup
\def\UD@ExtractFirstArgLoop#1{%
  \endgroup
  \@ifdefinable\UD@RemoveTillFrozenrelax{%
    \long\def\UD@RemoveTillFrozenrelax##1##2#1{{##1}}%
  }%
  \newcommand\UD@ExtractKthArgLoop[3]{%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo##3{}.}{\UD@stopromannumeral##2}{%
      \UD@CheckWhetherNull{##1}{%
        \UD@ExtractFirstArgLoop{##3#1}%
      }{%
        \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}##3}%
        {\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}##1}{##2}}%
      }%
    }%
  }%
}%
\expandafter\expandafter\expandafter\UD@ExtractFirstArgLoop
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\ifnum0=0\fi}%
%% Usage of frozen-\relax as delimiter is for speeding things up by reducing the
%% amount of iterations needed. I chose frozen-\relax because David Carlisle 
%% pointed out in   <https://tex.stackexchange.com/a/578877>
%% that frozen-\relax cannot be (re)defined in terms of \outer and cannot be
%% affected by \uppercase/\lowercase.
%%
%% \UD@ExtractFirstArg's argument may contain frozen-\relax:
%% The only effect is that internally more iterations are needed for
%% obtaining the result.
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {\expandafter\UD@stopromannumeral\UD@firstoftwo#1{}}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillFrozenrelax#1}}%
}%
%%=============================================================================
%% End of code for \ExtractKthArg.

\newcommand\ValueOfUndefinedVariable{\nfss@text{\reset@font\bfseries??}}%

\newcommand\RetrieveVariableIndex[3]{%
   \@ifundefined{Variables#1}{#3}{%
      \expandafter\expandafter\expandafter\UD@PassFirstToSecond
      \expandafter\expandafter\expandafter{\csname Variables#1\endcsname}{%
         \ExtractKthArg{#2}{#3}%
      }%
   }%
}%
\makeatother

\newcommand\VariablesA{%
   {Value of variable \texttt{A$_1$}.}%
   {Value of variable \texttt{A$_2$}.}%
   {Value of variable \texttt{A$_3$}.}%
   {Value of variable \texttt{A$_4$}.}%
}%
\newcommand\VariablesB{%
   {Value of variable \texttt{B$_1$}.}%
   {Value of variable \texttt{B$_2$}.}%
   {Value of variable \texttt{B$_3$}.}%
   {Value of variable \texttt{B$_4$}.}%
}%

\begin{document}

Extacting the value of variable \texttt{A$_1$} yields: \RetrieveVariableIndex{A}{1}{\ValueOfUndefinedVariable}

Extacting the value of variable \texttt{A$_2$} yields: \RetrieveVariableIndex{A}{2}{\ValueOfUndefinedVariable}

Extacting the value of variable \texttt{A$_3$} yields: \RetrieveVariableIndex{A}{3}{\ValueOfUndefinedVariable}

Extacting the value of variable \texttt{A$_4$} yields: \RetrieveVariableIndex{A}{4}{\ValueOfUndefinedVariable}

Extacting the value of variable \texttt{B$_1$} yields: \RetrieveVariableIndex{B}{1}{\ValueOfUndefinedVariable}

Extacting the value of variable \texttt{B$_2$} yields: \RetrieveVariableIndex{B}{2}{\ValueOfUndefinedVariable}

Extacting the value of variable \texttt{B$_3$} yields: \RetrieveVariableIndex{B}{3}{\ValueOfUndefinedVariable}

Extacting the value of variable \texttt{B$_4$} yields: \RetrieveVariableIndex{B}{4}{\ValueOfUndefinedVariable}

\end{document}

enter image description here

1
  • Thank you for taking the time to share this detailed response; I stand to learn more about LaTeX from this single answer than I have in the past 6+ months (!). Thank you for sharing your knowledge!
    – Rax Adaam
    Jul 25 at 16:58

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.