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?

2 Answers 2

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.

5
  • 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, 2017 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, 2017 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, 2017 at 9:31
  • 1
    @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, 2017 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, 2018 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}
1
  • 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, 2017 at 7:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .