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...

Didii
  • 1,323
  • 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
  • @Didii well yes and no, \c@count is the latex counter defined as in your question with \newcounter{count} just accessed differently. It's the same as \roman{count} except that it saves an expansion and 7 tokens (which probably mattered more in 1990 than it does now:-) – David Carlisle Jul 20 '12 at 13:25
  • @DavidCarlisle: makes sense :) I do have a problem now with the \def, for some reason I can't expand what I write as some data. I'll edit the question. – Didii Jul 20 '12 at 13:32
  • @Didii Use \edef instead of \def after \expandafter. – egreg Jul 20 '12 at 13:49
  • @egreg: Thanks, never heard of that command before :) – Didii Jul 20 '12 at 13:51
  • See http://tex.stackexchange.com/questions/63573/separate-style-and-content-in-table for an example. – user1189687 Jul 20 '12 at 14:01

1 Answers1

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.

egreg
  • 1,121,712
  • 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 09: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 09:06