Python-like dictionary in latex?

You can emulate it with a property list:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\DefineDictionary}{mm}
 {
  \arclupus_dict_def:nn { #1 } { #2 }
 }

\seq_new:N \l__arclupus_dict_temp_seq

\cs_new_protected:Nn \arclupus_dict_def:nn
 {
  \prop_gclear_new:c { g_arclupus_#1_dict_prop }
  \clist_map_inline:nn { #2 }
   {
    \__arclupus_dict_add:nn { #1 } { ##1 }
   }
  \cs_new:cpn { #1 } ##1 { \prop_item:cn { g_arclupus_#1_dict_prop } { ##1 } }
 }

\cs_new_protected:Nn \__arclupus_dict_add:nn
 {
  \seq_set_split:Nnn \l__arclupus_dict_temp_seq { / } { #2 }
  \prop_gput:cxx { g_arclupus_#1_dict_prop }
   {
    \seq_item:Nn \l__arclupus_dict_temp_seq { 1 }
   }
   {
    \seq_item:Nn \l__arclupus_dict_temp_seq { 2 }
   }
 }
\cs_generate_variant:Nn \prop_gput:Nnn { cxx }
\ExplSyntaxOff

\DefineDictionary{var}{a/1, b/2, c/3}

\begin{document}

\var{a}

\var{c}

\var{b}

\end{document}

The \DefineDictionary takes as argument the dictionary name and the data. A new property list is created (or an existing one is cleared); then each item in the second argument is split at / to become an item in the property list. Finally, a macro with the name of the dictionary is created to retrieve the data.

The version with the colon is slightly trickier, because we can't use a literal : for the split operation.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\DefineDictionary}{mm}
 {
  \arclupus_dict_def:nn { #1 } { #2 }
 }

\seq_new:N \l__arclupus_dict_temp_seq

\cs_new_protected:Nn \arclupus_dict_def:nn
 {
  \prop_gclear_new:c { g_arclupus_#1_dict_prop }
  \clist_map_inline:nn { #2 }
   {
    \__arclupus_dict_add:nn { #1 } { ##1 }
   }
  \cs_new:cpn { #1 } ##1 { \prop_item:cn { g_arclupus_#1_dict_prop } { ##1 } }
 }

\cs_new_protected:Nn \__arclupus_dict_add:nn
 {
  \seq_set_split:NVn \l__arclupus_dict_temp_seq \c_colon_str { #2 }
  \prop_gput:cxx { g_arclupus_#1_dict_prop }
   {
    \seq_item:Nn \l__arclupus_dict_temp_seq { 1 }
   }
   {
    \seq_item:Nn \l__arclupus_dict_temp_seq { 2 }
   }
 }
\cs_generate_variant:Nn \seq_set_split:Nnn { NV }
\cs_generate_variant:Nn \prop_gput:Nnn { cxx }
\ExplSyntaxOff

\DefineDictionary{var}{a:1, b:2, c:3}

\begin{document}

\var{a}

\var{c}

\var{b}

\end{document}

If you also need to pass macros to \var, then change the line

  \cs_new:cpn { #1 } ##1 { \prop_item:cn { g_arclupus_#1_dict_prop } { ##1 } }

into

  \cs_new:cpn { #1 } ##1 { \prop_item:cf { g_arclupus_#1_dict_prop } { ##1 } }

and add, just before \ExplSyntaxOff, the magic line

\cs_generate_variant:Nn \prop_item:Nn { cf }

that defines the required variant.

Macros that expand to strings are then welcome in the argument of the newly created macro (\var in the example). Note that \var is still fully expandable.


FWIW, ConTeXt has built-in data-structure that is equivalent to a dictionary. In particular,

\setvariables
    [var]
    [
      a=1,
      b=2,
      c=3,
    ]

Then you can access the variables using \getvariable{var}{a}, etc.

Using \def\abc{a} \getvariable{var}{\abc} also works.

Tags:

Code