使用 pgf 数组进行编程:如何创建数组?

使用 pgf 数组进行编程:如何创建数组?

我正在尝试在 tikz 中做一些自动绘图。重点是我希望能够为我的宏提供最少的信息,同时仍使其正常工作。

更准确地说(但不输入无用的细节),我想要获取一个坐标数组,对它们执行一些计算,并根据这些计算的结果绘制图片。

但无论我尝试采用哪种方式,我都会面临同样的问题:我需要处理坐标数组。由于\foreach语法\myarray[index],使用此类数组可以(或多或少)轻松地完成某些事情。一个很好的例子是这个问题

然而,一旦你尝试做更复杂的事情,困难就会出现。例如,如何对数组进行排序?如何将函数映射到数组的每个元素上?

如果我们能够轻松创建和/或修改数组,那么这一切似乎都很容易做到。但是,使用我所知道的命令,只能读取数组的内容。

因此,我尝试集中精力完成我能想象到但尚未完成的最简单的任务:将一个元素附加到数组的末尾。

由于我找不到任何纯粹的 pgf 方法来做到这一点,我尝试了一些低级黑客(大部分你可以在下面找到),但是pgf的语法重视括号,这使跟踪扩展过程变得非常困难,更不用说修复它了。

\documentclass{article}

\usepackage{tikz}

\newcommand{\printarray}[1]{\noindent
\foreach \i in #1 {\i\\}
}

\begin{document}

\def\myarraywithonebrace{1,2,3,4}
\def\myarraywithtwobraces{{1,2,3,4}}

\printarray{\myarraywithonebrace}
\printarray{\myarraywithtwobraces}

% Ok... So according to the manual, it's supposed to work better with two braces, 
% but then what am I doing wrong.

% Whatever, let's append an element
\def\mynewarraywithonebrace{\myarraywithonebrace,5}
\def\mynewarraywithtwobraces{\myarraywithtwobraces,5}

\printarray{\mynewarraywithonebrace}
\printarray{\mynewarraywithtwobraces}

% Ok, so it fails in both cases because it takes the array as a whole.
% Let's try appending sequencially each of its elements, then?

\def\mynewarraywithonebrace{\foreach \i in \myarraywithonebrace {\i, }5}
\def\mynewarraywithtwobraces{\foreach \i in \myarraywithtwobraces {\i, }5}

\printarray{\mynewarraywithonebrace}
\printarray{\mynewarraywithtwobraces}

% Now what... in each case I get a string instead of an array.

% Maybe it means it's time to add that extra pair of braces?

\def\mynewarraywithonebrace{{\foreach \i in \myarraywithonebrace {\i, }5}}
\def\mynewarraywithtwobraces{{\foreach \i in \myarraywithtwobraces {\i, }5}}

\printarray{\mynewarraywithonebrace}
\printarray{\mynewarraywithtwobraces}

% ... Nope

\end{document}

我的探索难道没有希望吗?

答案1

我认为这些 PGF 阵列不适合你的任务。

你可以使用我的一个实现,它可能更好。但是,尽管这个实现被证明是有用的,但它对 TeX 技能的要求相当高,而且没有真正的支持。

下面我会详细阐述这个实现。你可以先读一下,然后再回头考虑是否真的需要 TeX 中的数组,然后自行承担风险。

但这里有一个前言:数组是 TeX 中的某种弱点。

不要紧什么如果你想用数组来做任何事情,你总会遇到麻烦(而且我就遇到了很多麻烦)。

TeX 没有真正内置对数组的支持。PGF 也没有,尽管它的数学解析器可以解析此类列表。

您通常期望数组能够快速随机访问各个元素,并对“变量范围”进行一些明确定义的处理。

有几种数组实现。我看到其中一种是expl3前段时间写的。它们的主要问题是它们对“变量范围”和“速度”的解决方案。它们通常以与 PGF 数组类似的方式实现:作为包含文本分隔符的长宏。每当您访问或修改数组时,您都必须触摸每个元素。一个简单的循环

for i = 0; i<N; ++i
  append to array

通常具有 O(N^2) 时间要求。这适用于 PGF 数组和我在 expl3 中看到的实现。如果您必须以随机顺序访问 N 个元素,则相同的运行时要求成立。注意:我自己的包pgfplotstable是一个具有快速累积的混合包,但它也深受这个问题的困扰。它不是真正的数组实现,尽管它足以满足大多数较小的用例。

最终,我为“真实”数组编写了自己的实现,即随机访问需要 O(1) 成本的数组。它们的代价是它们很容易耗尽 TeX 内存,因为每个元素都存储在一个单独的宏中。它们的代价还在于这些数组无法删除(因为它们是全局的)或者它们只能存在于某个小范围内(即直到下一个\endgroup或右括号)。

它仅作为其中的一部分而存在pgfplots,并且其唯一的文档是代码注释pgfplotsarray.code.tex和一些测试用例。

这是我的测试用例的副本:

\pgfplotsarraynewempty\probe
\pgfplotsarraypushback eins\to\probe
\pgfplotsarraypushback [probe]\to\probe
\pgfplotsarraypushback [probe2]\to\probe
\pgfplotsarraypushback [probe3]\to\probe

Size: `\pgfplotsarraysize\probe\to{\count0}\the\count0'

Content:

\pgfplotsarrayforeach\probe\as\curarrayelem{\curarrayelem \par}

\testsubsection{Select}
Test list:

\pgfplotsarraynew\fooarray{Eins\\Zwei\\Drei\\}%
\pgfplotsarrayforeach\fooarray\as\foo{Element \foo\par}%

Getting elements:

\count1=1
Element \the\count1: \pgfplotsarrayselect\count1\of\fooarray\to\elem\elem

Element 2: \pgfplotsarrayselect2\of\fooarray\to\elem\elem

\vskip1cm


\testsubsection{Copy}

Copy:
\pgfplotsarraynew\fooarray{Eins\\Zwei\\Drei\\}%
Source: \pgfplotsarrayforeach\fooarray\as\foo{Element \foo\par}%

\pgfplotsarraycopy\fooarray\to\fooarrayX

Copy:   \pgfplotsarrayforeach\fooarrayX\as\foo{Element \foo\par}%

\testsubsection{reverse iter}
\pgfplotsarrayforeachreversed\probe\as\curarrayelem{\curarrayelem \par}

\testsubsection{reverse iter ungrouped}
\pgfplotsarrayforeachreversedungrouped\probe\as\curarrayelem{\curarrayelem \par}

\testsubsection{sort}
\pgfplotsarraynewempty\testarray
\pgfplotsarraypushback503\to\testarray
\pgfplotsarraypushback087\to\testarray
\pgfplotsarraypushback512\to\testarray
\pgfplotsarraypushback061\to\testarray
\pgfplotsarraypushback908\to\testarray
\pgfplotsarraypushback170\to\testarray
\pgfplotsarraypushback897\to\testarray
\pgfplotsarraypushback275\to\testarray
\pgfplotsarraypushback653\to\testarray
\pgfplotsarraypushback426\to\testarray
\pgfplotsarraypushback154\to\testarray
\pgfplotsarraypushback509\to\testarray
\pgfplotsarraypushback612\to\testarray
\pgfplotsarraypushback677\to\testarray
\pgfplotsarraypushback765\to\testarray
\pgfplotsarraypushback703\to\testarray

Unsorted: 

[\pgfplotsarrayforeach\testarray\as\elem{\elem\space}]

\pgfplotsarraysort\testarray

sorted: 

[\pgfplotsarrayforeach\testarray\as\elem{\elem\space}]

注意:通常,你只需要积累一长串项目并对其进行迭代。这要简单得多,尽管仍然需要付出很多努力才能避免积累的 O(N^2) 问题。对于这样的任务,有更有效的解决方案。

相关内容