Set n-th element of a sequence with xparse

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}

{
\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}
\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?

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}

{
\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}

\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.

• 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
\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}