我正在尝试在 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) 问题。对于这样的任务,有更有效的解决方案。