我已经分配了一个数组,我想设计一个带有 2 个值的命令(假设它名为\arraynum
),分别打印数组第一行和第二行中的元素数量,例如
\documentclass{article}
\usepackage{tikz}
\makeatletter
\ExplSyntaxOn
\cs_set:Npn \MyArray #1 {
\gdef\@MyArray{#1}
\gdef\@Arraynum{\clist_count:n {#1}}
\seq_set_split:Nnn \l_node_row_seq {;} {#1}
\int_step_inline:nn{\seq_count:N \l_node_row_seq}
{
\seq_if_exist:cF {l_node_row_##1_seq}
{
\seq_new:c {l_node_row_##1_seq}
}
\exp_args:Ncx\seq_set_from_clist:Nn {l_node_row_##1_seq} {\seq_item:Nn \l_node_row_seq{##1}}
}
}
\ExplSyntaxOff
\begin{document}
\MyArray{
1,2,3,4,5,6,7;
$\alpha$,$\beta$,$\gamma$,$\delta$,$\epsilon$
}
There are \@Arraynum{} elements in the array, 7 elements in the first line while 5 elements in the second line.
\end{document}
第一行有 7 个元素,因此命令\arraynum[1]{}
应该\arraynum[1]{@MyArray}
打印 7,而命令\arraynum[2]{@MyArray}
应该打印 5。那么,我该如何设计这个命令呢?
而且,如你所见,数组中总共有 12 个元素,而第一行和第二行之间以符号 分隔;
,但命令\clist_count:n {\@MyArray}
无法识别分隔符号;
,因此打印11
时正确的数字是12
。我该如何解决这些问题?
答案1
您可以更好地利用它expl3
,以便您可以定义任意数量的数组并以统一的方式从中检索信息。
一般来说,不要\gdef
与之混合expl3
。
请注意,下面的“步骤 2”命令是完全可扩展的。
步骤1。为阵列设置基础设施。
第2步。定义与这些数组一起使用的命令,例如“计数项目”或“检索一个项目”。
这是代码:数组被保存为 clist 序列。
\documentclass{article}
\ExplSyntaxOn
% step 1, set up arrays
\NewDocumentCommand{\definearray}{mm}
{
\seq_clear_new:c { l__axia_array_#1_seq }
\seq_set_split:cnn { l__axia_array_#1_seq } { ; } { #2 }
}
\cs_generate_variant:Nn \seq_set_split:Nnn { c }
% step 2, define commands to work with arrays
\NewExpandableDocumentCommand{\arraycount}{som}
{
\IfBooleanTF { #1 }
{
\seq_count:c { l__axia_array_#3_seq }
}
{
\IfNoValueTF { #2 }
{
\axia_array_count_full:n { #3 }
}
{
\axia_array_count_item:nn { #3 } { #2 }
}
}
}
\cs_new:Nn \axia_array_count_full:n
{
\int_eval:n
{
0
\seq_map_function:cN { l__axia_array_#1_seq } \__axia_array_count:n
}
}
\cs_new:Nn \__axia_array_count:n
{
+ \clist_count:n { #1 }
}
\cs_new:Nn \axia_array_count_item:nn
{
\clist_count:e { \seq_item:cn { l__axia_array_#1_seq } { #2 } }
}
\NewExpandableDocumentCommand{\arrayitem}{mmm}
{
\clist_item:en { \seq_item:cn { l__axia_array_#1_seq } { #2 } } { #3 }
}
\ExplSyntaxOff
\begin{document}
\definearray{MyArray}{
1,2,3,4,5,6,7;
$\alpha$,$\beta$,$\gamma$,$\delta$,$\epsilon$
}
There are \arraycount{MyArray} elements in the array,
\arraycount[1]{MyArray} elements in the first line and
\arraycount[2]{MyArray} elements in the second line.
There are \arraycount*{MyArray} lines in the array.
The third item in the second line is \arrayitem{MyArray}{2}{3}.
\end{document}
您会看到\arraycount
计算全长;如果您传递一个可选参数,您将获得相应行的长度;相反,\arraycount*{<name>}
计算行数。
您可以通过以下方式测试完整的可扩展性
\edef\testA{\arraycount*{MyArray}}
\edef\testB{\arraycount{MyArray}}
\edef\testC{\arraycount[1]{MyArray}}
\texttt{\meaning\testA}\par
\texttt{\meaning\testB}\par
\texttt{\meaning\testC}
您可以在同一文档中
\definearray{Another}{aaa,bbb,ccc;ddd,eee;fff,ggg,hhh;iiii}
\arraycount{Another}
\arraycount*{Another}
\arraycount[1]{Another}--%
\arraycount[2]{Another}--%
\arraycount[3]{Another}--%
\arraycount[4]{Another}
你会得到
答案2
使用listofitems
, 代替 expl3:
\documentclass{article}
\usepackage{listofitems}
\newtoks\zz
\newcommand\addtozz[1]{\global\zz\expandafter{\the\zz#1}}
\newcommand\xaddtozz[1]{\expandafter\addtozz\expandafter{#1}}
\newcommand\xxaddtozz[1]{\expandafter\xaddtozz\expandafter{#1}}
\setsepchar{;/,}
\newcommand\TotalElements{\zz{}%
\foreachitem\z\in\MyArray[]{%
\ifnum\zcnt=1 \else\addtozz{+}\fi
\xxaddtozz{\listlen\MyArray[\zcnt]}%
}%
\the\numexpr\the\zz\relax
}
\begin{document}
\readlist*\MyArray{
1,2,3,4,5,6,7;
$\alpha$,$\beta$,$\gamma$,$\delta$,$\epsilon$
}
There are \TotalElements{} elements in the array, \listlen\MyArray[1] elements
in the first line while \listlen\MyArray[2] elements in the second line.
\end{document}
由于计数器是全局的,因此实际上使用它们比使用标记列表更容易,可以进行计数\TotalElements
:
\documentclass{article}
\usepackage{listofitems}
\newcounter{zz}
\setsepchar{;/,}
\newcommand\TotalElements{\setcounter{zz}{0}%
\foreachitem\z\in\MyArray[]{%
\addtocounter{zz}{\listlen\MyArray[\zcnt]}%
}%
\thezz
}
\begin{document}
\readlist*\MyArray{
1,2,3,4,5,6,7;
$\alpha$,$\beta$,$\gamma$,$\delta$,$\epsilon$
}
There are \TotalElements{} elements in the array, \listlen\MyArray[1] elements
in the first line while \listlen\MyArray[2] elements in the second line.
\end{document}