1

I need a list of counters with the special requirement that I a-priori don't know how many counters are needed. My first idea is to use a sequence of integers that has a variable length. As suggested by egreg's answer to

Get n-th element of a list (with etoolbox, or not)

I want to use the xparse package. If there is an easier solution, feel free to tell me.

Egreg's code allows to predefine the list, add elements and read the n-th element. However, I also want to increase a specific element of the list (by 1) every time another command is run. But, honestly I am having a hard time with the syntax. I tried to write a function \setnthelement that has the optional argument (the identifier of the sequence) and two mandatory arguments: the first shall be the list index to be changed and the second the new value of the list at the specified index. I use the following code

\documentclass[10pt]{scrartcl}
\usepackage{xparse}
\ExplSyntaxOn    
\NewDocumentCommand{\newchangelist}{ m }
 {
  \seq_new:c { g_change_#1_seq }
 }

\newchangelist{changelist}

\NewDocumentCommand{\addtochangelist}{ O{changelist} m }
 {
  \seq_gput_right:cn { g_change_#1_seq } { #2 }
 }
\NewDocumentCommand{\getnthelement}{ O{changelist} m }
 {
  \seq_item:cn { g_change_#1_seq } { #2 }
 }
\NewDocumentCommand{\setnthelement}{ O{changelist} m m } %not working
 {
  \cs_set:Npx{\seq_item:cn{g_change_#1_seq}{#2}{#3}}
 }
\ExplSyntaxOff
\begin{document}
\addtochangelist{1}
\addtochangelist{0}
\addtochangelist{3}
\getnthelement{2}
%\setnthelement{1}{2}
%\setnthelement{2}{\getnthelement{2}+1}
%\getnthelement{2} %should now return 0+1=1)
\end{document}

If any of the \setnthelement lines is activated, I obtain an error like

Missing control sequence inserted. \setnthelement{1}{2}

Obviously my code for \setnthelement is wrong. Furthermore, I guess that the addition won't be that easy, so a solution for this problem is also welcome, but I can probably figure out that on my own.

Can you please help me and tell me how to set the value of a list at a specific index?

1

You can't modify an element of a sequence by just addressing it. I think you're using the wrong tool for your purpose, probably a property list is better.

Anyway, here's how you can do: you just rebuild the sequence.

In order to do arithmetic, the \getnthelement command must be made expandable and \inteval from the xfp package is needed.

\documentclass[10pt]{scrartcl}
\usepackage{xparse,xfp}

\ExplSyntaxOn    

\NewDocumentCommand{\newchangelist}{ m }
 {
  \seq_new:c { g_change_#1_seq }
 }

\newchangelist{changelist}

\NewDocumentCommand{\addtochangelist}{ O{changelist} m }
 {
  \seq_gput_right:cn { g_change_#1_seq } { #2 }
 }
\NewExpandableDocumentCommand{\getnthelement}{ O{changelist} m }
 {
  \seq_item:cn { g_change_#1_seq } { #2 }
 }

\NewDocumentCommand{\setnthelement}{ O{changelist} m m }
 {
  \seq_clear:N \l_tmpa_tl
  \int_step_inline:nnnn { 1 } { 1 } { #2 - 1 }
   {
    \seq_put_right:Nx \l_tmpa_tl { \seq_item:cn { g_change_#1_seq } { ##1 } }
   }
  \seq_put_right:Nx \l_tmpa_tl { #3 }
  \int_step_inline:nnnn { #2 + 1 } { 1 } { \seq_count:c { g_change_#1_seq } }
   {
    \seq_put_right:Nx \l_tmpa_tl { \seq_item:cn { g_change_#1_seq } { ##1 } }
   }
  \seq_gset_eq:cN { g_change_#1_seq } \l_tmpa_tl
 }

\ExplSyntaxOff

\begin{document}

\addtochangelist{1}
\addtochangelist{0}
\addtochangelist{3}
\getnthelement{2}
\setnthelement{1}{2}
\setnthelement{2}{\inteval{\getnthelement{2}+1}}
\getnthelement{2}

\end{document}

This prints

0 1

Checking whether one's trying to get past the current length of the sequence could be added.

| improve this answer | |
  • Thank you very much, egreg! The \setntheelement method works perfectly. Unfortunately, I have no xfp package on my company's computer installed and therefore I obtain: "Undefined control sequence. \setnthelement{2}{\inteval{\getnthelement{2}+1}}." I am only confused because there is no error message for the line where I Input "\usepackage{xfp}". – TP1987 Dec 21 '17 at 7:09
  • The intcalc package is available and now I use its function \intcalcInc like this: \setnthelement{2}{\intcalcInc{\getnthelement{2}}} That was much easier to figure out than setting the element of the list, so thanks again, egreg! – TP1987 Dec 21 '17 at 7:34
  • Well, it worked in the minimal example, but in my real document it doesn't. The error is "Missing number, treated as zero. \setnthelement{2}{\intcalcInc{\getnthelement{2}}}". There is also a missing number error, if I just use "\intcalcInc{\getnthelement{2}". Do you know, how to fix the problem? Maybe I should switch to the property list that you mentioned. Do you have a reference for this? – TP1987 Dec 21 '17 at 9:31
  • @TP1987 If \inteval raises an error, you can add \ProvideExpandableDocumentCommand{\inteval}{m}{\int_eval:n{#1}} just after \ExplSyntaxOn. Your system has, apparently, an older release of expl3. – egreg Dec 21 '17 at 9:37
  • Thanks @egreg! It works like a charm :). You really must not forget to make the \getnthelement method expandable otherwise \inteval will not work (that was my first mistake). – TP1987 Feb 7 '18 at 8:17
0
\documentclass{scrartcl}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand \newchangelist { m }
 {
  \seq_new:c { g_change_#1_seq }
 }

\newchangelist{changelist}

\NewDocumentCommand \addtochangelist { O{changelist} m }
 {
  \seq_gput_right:cn { g_change_#1_seq } { #2 }
 }

\NewDocumentCommand \getnthelement { O{changelist} m }
 {
  \seq_item:cn { g_change_#1_seq } { #2 }
 }

\NewDocumentCommand \setnthelement { O{changelist} m m }
 {
  \seq_clear:N \l_tmpa_seq
  \int_zero:N \l_tmpa_int
  \seq_map_inline:Nn \l_tmpa_seq
   {
    \int_incr:N \l_tmpa_int
    \int_compare:nNnTF { \l_tmpa_int } = { #2 }
     { \seq_put_right:Nn \l_tmpa_seq { #3  } }
     { \seq_put_right:Nn \l_tmpa_seq { ##1 } }
   }
  \seq_gset_eq:cN { g_change_#1_seq } \l_tmpa_seq
 }

\ExplSyntaxOff

\begin{document}

\addtochangelist{1}
\addtochangelist{0}
\addtochangelist{3}
\getnthelement{2}
\setnthelement{1}{2}
\setnthelement{2}{\getnthelement{2}+1}
\getnthelement{2} %should now return 0+1=1)

\end{document}
| improve this answer | |
  • Thanks, Manuel. Your code does not seem to solve my problem. I obtain only "0" as Output. Particularly, I am not sure why only a single number is returned although \getnthelement is called two times. Does your code delete the list? – TP1987 Dec 21 '17 at 7:24

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.