如何找到 PGF 数组的长度,即使它在宏中?

如何找到 PGF 数组的长度,即使它在宏中?

答案之一关于如何计算PGF数组的长度的问题提供了一个函数,该函数为其参数提供的数组上迭代的每个步骤增加一个计数器。

但是,如果我将一个数组存储在一个变量中,\def\myarray{{1,2,3,4,5,6}}然后使用\arrayLength{\myarray},则输出的是数字 1,而不是 6。我相信这与如何扩展有关\myarray,但不明白是什么。\expandafter\arrayLength{\myarray}也输出 1。

一个函数如何才能\len正确输出数组中元素的数量,无论是\len{{1,2,3}}还是\len{\myarray}

一位 MWE 表示:

\documentclass[tikz]{standalone}

\newcounter{arraycard}
\def\arrayLength#1{%
 \setcounter{arraycard}{0}%
 \foreach \x in #1{%
   \stepcounter{arraycard}%
 }%
 \the\value{arraycard}%
 } 

 \begin{document}
 The length of $\{1,2,3\}$ is \arrayLength{{1,2,3}}.

 The length of $\{1,2,\{3,4\},5\}$ is \arrayLength{{1,2,{3,4},5}}.

 \def\myarray{{1,2,3,4,5,6}}
 The length of \verb|\myarray| is \arrayLength{\myarray}.
\end{document}

答案1

你想在计算之前展开宏,所以

在此处输入图片描述

\documentclass[tikz]{standalone}

\newcounter{arraycard}
\def\arrayLength#1{\expandafter\xarraylength\expandafter{#1}}%
\def\xarraylength#1{%
 \setcounter{arraycard}{0}%
 \foreach \x in #1{%
   \stepcounter{arraycard}%
 }%
 \the\value{arraycard}%
 } 

 \begin{document}
 The length of is \arrayLength{{\newcounter,\begin,\tikz}}.


 \def\myarray{{\newcounter,\begin,\tikz}}
 The length of \verb|\myarray| is \arrayLength\myarray.
\end{document}

答案2

其中一个版本\arrayLength检查参数中的第一个标记是否是第二个左括号,如果是,则检查内部组后面是否没有任何内容,如果是,则计算元素。如果第一个标记不是左括号,则将第一个标记展开一次,再次测试第一个标记是否是左括号,并且内部组后面没有任何内容,如果是,则计算元素。如果参数未通过这些测试,则会抛出错误并返回 0。

该宏是完全可扩展的。

\documentclass[border=3.14]{standalone}

\usepackage{xparse}
\ExplSyntaxOn
\group_begin:
\char_set_catcode_letter:n { 32 }% spaces are letters until the next \group_end:
\cs_new:Npn\__xarrayLength_bad_argument:{\xarrayLength error: no TikZ array}%
\group_end:%
\NewExpandableDocumentCommand \xarrayLength { +m }
  {
    \tl_if_head_is_group:nTF { #1 }
      { \__xarrayLength_count_first_group:nw #1 \q_stop }
      { \__xarrayLength_aux:o { #1 } }
  }
\cs_new:Npx \__xarrayLength_aux:n #1
  {
    \exp_not:N \tl_if_head_is_group:nTF { #1 }
      { \exp_not:N \__xarrayLength_count_first_group:nw #1 \exp_not:N \q_stop }
      { \exp_after:wN \exp_not:N \__xarrayLength_bad_argument: 0 }
  }
\cs_generate_variant:Nn \__xarrayLength_aux:n { o }
\cs_new:Npx \__xarrayLength_count_first_group:nw #1 #2 \q_stop
  {
    \exp_not:N \tl_if_empty:nTF { #2 }
      { \exp_not:N \clist_count:n { #1 } }
      { \exp_after:wN \exp_not:N \__xarrayLength_bad_argument: 0 }
  }
\ExplSyntaxOff

\newcommand\myarray{{1,2,3,4,5,6}}

\newcounter{elements}

\begin{document}
% \setcounter to prove it is expandable
\setcounter{elements}{\xarrayLength{\myarray}}\arabic{elements}
\xarrayLength{{1,2,3,4,5,6}}
\renewcommand\myarray{1,2,3,4,5,6}%
% \setcounter to prove it is expandable
\setcounter{elements}{\xarrayLength{\myarray}}\arabic{elements}
\xarrayLength{1,2,3,4,5,6}
\end{document}

在此处输入图片描述

答案3

由于您使用的是 PGF 数组(始终用“双括号”表示),因此expl3一行代码就足够了:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\arrayLength}{m}
 {% #1 = explicit or implicit array
  \diniz_array_length:o { #1 }
 }
\cs_new:Nn \diniz_array_length:n
 {
  \clist_count:n #1
 }
\cs_generate_variant:Nn \diniz_array_length:n { o }
\ExplSyntaxOff

\begin{document}

The length of $\{1,2,3\}$ is \arrayLength{{1,2,3}}.

The length of $\{1,2,\{3,4\},5\}$ is \arrayLength{{1,2,{3,4},5}}.

\def\myarray{{1,2,3,4,5,6}}

The length of \verb|\myarray| is \arrayLength{\myarray}.

\end{document}

在此处输入图片描述

如果您想要最后一项的位置,根据 PGF 约定,它是项数减一,因为索引从 0 开始。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\arrayLength}{m}
 {% #1 = explicit or implicit array
  \diniz_array_length:o { #1 }
 }
\cs_new:Nn \diniz_array_length:n
 {
  \int_eval:n { \clist_count:n #1 - 1 }
 }
\cs_generate_variant:Nn \diniz_array_length:n { o }
\ExplSyntaxOff

\begin{document}

The length of $\{1,2,3\}$ is \arrayLength{{1,2,3}}.

The length of $\{1,2,\{3,4\},5\}$ is \arrayLength{{1,2,{3,4},5}}.

\def\myarray{{1,2,3,4,5,6}}

The length of \verb|\myarray| is \arrayLength{\myarray}.

\end{document}

这里的答案是 2、3 和 5。

诀窍在于,如果您调用\arrayLength{{1,2,3}}o变体将尝试扩展{,这显然不执行任何操作;在 的情况下,\arrayLength{\myarray}宏将根据需要扩展一次。请注意 将{1,2,3}是 的参数\clist_count:n,因此将删除括号。

还要注意,这是完全可扩展的(可以进入\edef)。

答案4

我有时在代码中解决这个问题的方法是

\documentclass[tikz]{standalone}

\newcounter{arraycard}
\def\arrayLength#1{%
 \setcounter{arraycard}{0}%
 \edef\temp{\noexpand\foreach \noexpand\x in #1{%
   \noexpand\stepcounter{arraycard}%
 }}%
 \temp
 \the\value{arraycard}%
 } 

 \begin{document}
 The length of $\{1,2,3\}$ is \arrayLength{{1,2,3}}.

 The length of $\{1,2,\{3,4\},5\}$ is \arrayLength{{1,2,{3,4},5}}.

 \def\myarray{{1,2,3,4,5,6}}
 The length of \verb|\myarray| is \arrayLength\myarray.
\end{document}

在此处输入图片描述

很可能会有同等的东西,但我个人不太\expandafter喜欢。\expandafter

相关内容