![可以避免在这个涉及 TikZ 的宏中输入双引号吗?](https://linux22.com/image/304528/%E5%8F%AF%E4%BB%A5%E9%81%BF%E5%85%8D%E5%9C%A8%E8%BF%99%E4%B8%AA%E6%B6%89%E5%8F%8A%20TikZ%20%E7%9A%84%E5%AE%8F%E4%B8%AD%E8%BE%93%E5%85%A5%E5%8F%8C%E5%BC%95%E5%8F%B7%E5%90%97%EF%BC%9F.png)
我需要绘制许多类似的复杂彩色形状;我为它们制作了一个宏,它可以工作,但要调用它,我似乎必须将几个颜色名称放在双引号中。我可以避免这种情况吗?
我给出的例子是简化的,我需要的是不同的,但这个例子(希望)能给出这个想法。
\documentclass{amsart}
\usepackage{tikz}
\def\sillyexample#1#2{
\newcount\p
\foreach\i in {#1}
{
\foreach\j in {1,...,\i}
{
\pgfmathparse{{#2}[\j+\the\p-1]}
\node [\pgfmathresult] at (\j+\the\p,0) {\i};
}
\global\advance\p by \i
}
}
\begin{document}
\begin{tikzpicture}
\sillyexample{2,3,1}{"red","blue","green","green","cyan","blue"}
\end{tikzpicture}
\end{document}
正如我所说,这是有效的,结果
正如预期的那样,我唯一想要的是我是否可以避免在调用中在颜色名称周围使用所有这些双引号。
好吧,而且 - 因为我无论如何都要问 - 我的代码可以通过其他方式改进吗?
答案1
这里我只是创建一个递归辅助例程\addquotes
。
\documentclass{amsart}
\usepackage{tikz}
\def\sillyexample#1#2{
\newcount\p
\foreach\i in {#1}
{
\foreach\j in {1,...,\i}
{
\pgfmathparse{{\addquotes#2,\relax}[\j+\the\p-1]}
\node [\pgfmathresult] at (\j+\the\p,0) {\i};
}
\global\advance\p by \i
}
}
\def\addquotes#1,#2\relax{"#1",\if\relax#2\relax\else\addquotes#2\relax\fi}
\begin{document}
\begin{tikzpicture}
\sillyexample{2,3,1}{red,blue,green,green,cyan,blue}
\end{tikzpicture}
\end{document}
答案2
LaTeX 内核具有处理逗号分隔列表的功能:
\documentclass{amsart}
\usepackage{tikz}
\newcount\p
\def\sillyexample#1#2{%
\p=0
\addquotes\sillyexampleargtwo{#2}%
\foreach\i in {#1}%
{%
\foreach\j in {1,...,\i}%
{%
\pgfmathparse{{\sillyexampleargtwo}[\j+\the\p-1]}%
\node [\pgfmathresult] at (\j+\the\p,0) {\i};%
}%
\global\advance\p by \i
}%
}
\makeatletter
\newcommand\addquotes[2]{%
\def#1{\@gobble}%
\@for\next:=#2\do{%
\edef#1{#1,\string"\next\string"}%
}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
\sillyexample{2,3,1}{red,blue,green,green,cyan,blue}
\end{tikzpicture}
\end{document}
该\addquotes
宏遍历给定的列表,并使用双引号之间的每个项目构建一个新的列表。
始终小心并放置\newcount
指示外部\sillyexample
定义。使用你的代码,每次调用宏时都会分配一个新的计数器。\p
实际上,这也不是一个好名字。
答案3
无需使用任何额外的宏或包,这是一个以线性时间运行的解决方案O(k)
,即在中是线性的k
,其中k
是颜色的数量(在您的帖子中等于 6)。这全是关于条件的。我在这里使用的两个条件是:
\ifnum \k > \p{
\ifnum \k < \numexpr\num+\p+1 \relax
...
这些条件精确地选取了将每个数字与其颜色配对所需的值。通过运行(按顺序)可获得以下结果:
\lesssillyexample{2,3,1}{red,blue,green,green,cyan,blue}
\lesssillyexample{5,3,2}{red,blue,green,green,cyan,blue,red,blue,green,green}
\lesssillyexample{3,2,3,1,2}{red,blue,green,green,cyan,blue,red,blue,green,green,red}
完整代码如下:
\documentclass{amsart}
\usepackage{tikz}
\newcount\p
\def\lesssillyexample#1#2{
\p=0
\foreach \num in {#1}
{
\foreach [count=\k]\kthcolor in {#2}
{
\ifnum \k > \p{
\ifnum \k < \numexpr\num+\p+1 \relax
\node at(\k,0)[\kthcolor]{\num};
\fi}
\fi
}
\global\advance\p by \num
}
}
\begin{document}
\begin{tikzpicture}
\lesssillyexample{2,3,1}{red,blue,green,green,cyan,blue}
\end{tikzpicture}
\end{document}
答案4
上述 John Kormylo 的评论虽然我至今还不明白,但却给了我一些提示。他提供了另一个问题的答案的链接;另一个答案这个问题启发了这个解决方案:
\documentclass{amsart}
\usepackage{tikz}
\def\lesssillyexample#1#2{
\newcount\p
\foreach\i in {#1}
{
\foreach\j in {1,...,\i}
{
\foreach[count=\k] \kthcolor in {#2}
{
\ifnum \k = \the\numexpr\j+\the\p\relax
\node [\kthcolor] at (\k,0) {\i};
\breakforeach
\fi
}
}
\global\advance\p by \i
}
}
\begin{document}
\begin{tikzpicture}
\lesssillyexample{2,3,1}{red,blue,green,green,cyan,blue}
\end{tikzpicture}
\end{document}
这种方法是可行的,但代价是,不是从颜色数组的所需位置挑选条目,而是每次从头开始扫描数组,直到到达该位置,这非常低效且不雅致。因此,尽管我将其作为答案发布,但我不会接受它。也许有人可以改进它或提出不同的建议。