使用 xparse 设置序列的第 n 个元素

使用 xparse 设置序列的第 n 个元素

我需要一个计数器列表,但有一个特殊要求,即我事先不知道需要多少个计数器。我的第一个想法是使用一个长度可变的整数序列。正如 egreg 对

获取列表的第 n 个元素(使用 etoolbox,或不使用)

我想使用 xparse 包。如果有更简单的解决方案,请告诉我。

Egreg 的代码允许预定义列表、添加元素并读取第 n 个元素。但是,每次运行另一个命令时,我还想增加列表中的特定元素(增加 1)。但老实说,我对语法感到困惑。我尝试编写一个\setnthelement具有可选参数(序列的标识符)和两个强制参数的函数:第一个参数应为要更改的列表索引,第二个参数应为指定索引处列表的新值。我使用以下代码

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

如果任何一条\setnthelement线路被激活,我就会收到类似的错误

插入了缺失的控制序列。\setnthelement{1}{2}

显然我的代码\setnthelement是错误的。此外,我猜添加不会那么容易,所以也欢迎解决这个问题,但我可能可以自己解决这个问题。

您能帮助我并告诉我如何在特定索引处设置列表的值吗?

答案1

您不能仅通过寻址来修改序列中的元素。我认为您使用的工具不适合您的目的,属性列表可能更好。

无论如何,您可以这样做:重建序列。

为了进行算术运算,\getnthelement必须使命令可扩展,并且需要\inteval从包中获取。xfp

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

这将打印

0 1

可以添加检查是否有人试图超出序列的当前长度。

答案2

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

相关内容