3

I regularely use lists defined with pgfmath and encountered an error if one of the list items is "33" but not " 33" or "32".... Please find below a minimal example to reproduce the error. Thanks to anyone that could help me correct this issue.

\documentclass{minimal}
\usepackage{pgfmath}
\makeatletter
\def\pgfmathdeclarelist#1#2{%
    \def\pgfmath@list@name{#1}% 
    \c@pgfmath@counta=0% 
    \pgfmath@declarelistlist#2{\pgfmath@stop}% 
}
\def\pgfmath@declarelistlist#1{%
    \ifx#1\pgfmath@stop%
        \expandafter\edef\csname pgfmath@list@\pgfmath@list@name @length\endcsname{\the\c@pgfmath@counta}% 
    \else% 
        \advance\c@pgfmath@counta by1\relax% 
        \pgfutil@namedef{pgfmath@list@\pgfmath@list@name @\the\c@pgfmath@counta}{#1}% 
        \expandafter\pgfmath@declarelistlist% 
    \fi% 
}
\makeatother

\begin{document} \pgfmathdeclarelist{list}{{33}} \end{document}

laurent
  • 41
  • 1

1 Answers1

0

I guess you also have commands for retrieving items from those lists, something like

\def\pgfmathlistitem#1#2{%
  \ifnum \csname pgfmath@list@\pgfmath@list@name @length\endcsname<#2
  \else
    \csname pgfmath@list@#1@#2\endcsname
  \fi
}

so you can do \pgfmathdeclarelist{list}{{3}{5}{6}{7}} and with \pgfmathlistitem{list}{2} you get 5.

The approach will fail, as you saw, if an item starts with two equal tokens, because you're doing

\ifx#1

and if #1 is 33 the test returns true.

You can do it much more simply.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\declarelist}{mm} { \seq_clear_new:c { l_laurent_list_#1_seq } \tl_map_inline:nn { #2 } { \seq_put_right:cn { l_laurent_list_#1_seq } { ##1 } } }

\NewExpandableDocumentCommand{\listitem}{mm} { \int_compare:nTF { #2 == 0 } {% return the list length \seq_count:c { l_laurent_list_#1_seq } } {% return the item \seq_item:cn { l_laurent_list_#1_seq } { #2 } } }

\ExplSyntaxOff

\begin{document}

\declarelist{list}{{33}{5}{6}{7}}

``\listitem{list}{1}'' should print 33

``\listitem{list}{0}'' should print 4

``\listitem{list}{-1}'' should print 7

\end{document}

With a negative argument, items are selected from the end.

enter image description here

Instead of using several \csname tokens, I use an expl3 sequence. At declaration time, the given braced items are put in the sequence and we can use the built-in method for retrieving items. No need to reinvent the wheel.

It would be possible to add a check that the second argument to \listitem doesn't exceed the list length and also a check that the list has been declared.

egreg
  • 1,121,712
  • Indeed. Thanks for your solution. I'll see if I can redefine it this way without breaking all dependencies in my code, ie list length, get, set, shuffle commands. – laurent Mar 29 '23 at 11:31
  • @laurent I already provided for the list length (pass 0 as argument). In expl3 there's \seq_shuffle:c that should be what you need. – egreg Mar 29 '23 at 11:52
  • yep seen that, thanks. It's just that I use those lists very often in multiple choice test questions with tikz drawings so I have to check if this new LaTeX3 codes compiles well with it. – laurent Mar 29 '23 at 12:00