7

Is there a way to add an index to a command? For example:

\newcounter{count}
\loop<condition>
  \def\var\Roman{count}{some data}
\repeat

The \var\Roman{count} should become the variable \varI, \varII, \varIII and so on.

Background: I need to get some data from external files and store it into variables (which I will later use to create a document). Normally every \varI should be the same as every \varII, but I need to check whether it really is the case or not. If not I should return a warning or error.


Solution for the first problem is in the comments, but I have a second problem.

Suppose I wrote this:

\newcommand\addindex[3]{  % #1 as name of var, #2 as index and #3 as content
  \expandafter\def\csname #1\Roman{#2}\endcsname{#3}  % thanks to egreg
}

\newcounter{count}
\loop\unless\ifnum\value{count}=5
  \stepcounter{count}
  \addindex{var}{count}{\arabic{count}}
\repeat

All \var<index> have now as value 5, because they are defined as \arabic{count}, and not their value at the moment. Adding \expandafter before \arabic{count} does not seem to work for some reason...

  • 2
    \@namedef{var\romannumeral\c@count}{some data} – David Carlisle Jul 20 '12 at 11:59
  • 1
    Or \expandafter\def\csname var\Roman{count}\endcsname{...} – egreg Jul 20 '12 at 12:50
  • Thanks again egreg, I'm starting to like you :p @DavidCarlisle: thanks, but in that way I have to use TeX counters instead of LaTeX counters. I prefer the LaTeX way :) – Didii Jul 20 '12 at 13:12
  • Also, is there a way to read them again using another loop? I can't seem to find out how for the moment... – Didii Jul 20 '12 at 13:12
  • Figured it out, I could just use the \csname environment again :) – Didii Jul 20 '12 at 13:23
8

The method is quite simple, but I add a trick that can be useful in your application:

\newcounter{tempcount} % for temporary usage

\newcommand\addindex[4][]{% #2 as name of var, #3 as index and #4 as content
  \csname#1def\expandafter\endcsname\csname #2\Roman{#3}\endcsname{#4}%
}

Now we want to define \varI, \varII, \varIII and \varIV to expand to some text:

\setcounter{tempcount}{0}

\loop\ifnum\value{tempcount}<4
  \stepcounter{tempcount}
  \addindex{var}{tempcount}{some text}
\repeat

If instead you want that \varI expands to 1 and so on, here's the role of the optional argument:

\setcounter{tempcount}{0}

\loop\ifnum\value{tempcount}<4
  \stepcounter{tempcount}
  \addindex[e]{var}{tempcount}{\arabic{tempcount}}
\repeat

By passing e as the optional argument, what's executed is \csname edef\endcsname, that is \edef that expands completely the replacement text before doing the definition. With no optional argument only \def is used.

A more efficient definition would be of \vari, \varii and so on (with lowercase roman numbers):

\newcommand\addindex[4][]{% #2 as name of var, #3 as index and #4 as content
  \csname#1def\expandafter\endcsname\csname #2\roman{#3}\endcsname{#4}%
}

It's more efficient because \Roman{tempcount} has to scan each character in the expansion of \roman{tempcount} and change it to its uppercase counterpart, while \roman{tempcount} expands to \romannumeral\c@tempcount using the TeX primitive \romannumeral, which is quite fast.

  • Why is the \expandafter needed? I'm currently searching what it exactly does, but can't seem to find it easily.. – Didii Jul 23 '12 at 9:54
  • 1
    The \expandafter last before \endcsname is necessary so that the following \csname is processed before TeX forms the token \def or \edef. So when the counter's value is 1, for instance, what TeX will see is \def\varI. Without the \expandafter it would see \def\csname varI\endcsname which is wrong. – egreg Jul 23 '12 at 10:55
  • I finally found a question which answers that :). Thanks. – Didii Jul 24 '12 at 9:06

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.