1

I often need to define macros whose name contains the value of a counter, notably to attribute a value to multiple objects: in python I would do:

myArray[0] = "mystyle"

Unfortunately, I can't use \expandafter\xdef\csname myArray\the\mycounter\endcsname because in LaTeX, it is not possible to have numbers in macros. For now I'm using \roman{mycounter} instead, but it feels very hacky as it can take a long time to computer the roman version of a number... Is there any better solution? I tried notably to check if LaTeX3 provided something better for this kind of associative arrays containing numbers, but I can only find integers arrays (I guess integers that can only contain arrays). The other option I imagine is maybe a sequence of tupples, but then the access time is linear which is not very efficient.

MWE

\documentclass[options]{article}

\begin{document}

\newcounter{mycounter}

\expandafter\edef\csname myArray\roman{mycounter}\endcsname{Hello}

Bonjour'' is\csname myArray\roman{mycounter}\endcsname''.

\end{document}

tobiasBora
  • 8,684

2 Answers2

3

If you define

\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\cs#1{\csname#1\endcsname}

then an equivalent of python's

myArray[0] = "mystyle"

is

\sdef{myArray[0]}{mystyle}

and the value is accessible by

\cs{myArray[0]}

You can declare a counter by \newcount\mycount and then you can extend the example above by replacing the 0 character by \the\mycount:

\newcount\mycount

\sdef{myArray[\the\mycount]}{mystyle} \cs{myArray[\the\mycount]}

wipet
  • 74,238
1

If you're afraid of the access time to a sequence, you can use \csname:

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\newarray}{m} { % keep the next free index \int_new:c { g__tobias_array_#1_int } } \NewDocumentCommand{\addtoarray}{omm} { \tobias_array_add:enn {% the index \IfNoValueTF { #1 } { \int_eval:n { \int_use:c { g__tobias_array_#2_int } } } { \int_eval:n { #1 } } } { #2 } % the array { #3 } } \NewExpandableDocumentCommand{\getarray}{mm} { \tobias_array_get:ne { #1 } { \int_eval:n { #2 } } }

\cs_new_protected:Nn \tobias_array_add:nnn { \tl_gclear_new:c { g__tobias_array_#2_#1_tl } \tl_gset:cn { g__tobias_array_#2_#1_tl } { #3 } \int_gset:cn { g__tobias_array_#2_int } { #1 + 1 } } \cs_generate_variant:Nn \tobias_array_add:nnn { e }

\cs_new:Nn \tobias_array_get:nn { \tl_if_exist:cT { g__tobias_array_#1_#2_tl } { \tl_use:c { g__tobias_array_#1_#2_tl } } } \cs_generate_variant:Nn \tobias_array_get:nn { ne }

\ExplSyntaxOff

\begin{document}

\newarray{myarray} \addtoarray{myarray}{An item} \addtoarray{myarray}{Another item} \addtoarray[1+3]{myarray}{Item #4}

0: \getarray{myarray}{0}

1: \getarray{myarray}{1}

3: \getarray{myarray}{3}

4: \getarray{myarray}{2+2}

\end{document}

You can add to an array sequentially or even jumping over some indices. And do arithmetic in order to find or set an index.

In the example, the next \addtoarray would use index 5.

enter image description here

egreg
  • 1,121,712