我想\foreach
在里面使用\edef
,例如定义一组随机点,如下所示:
\edef\mypoints{%
\foreach \x in {0,.1,...,1}
{\pgfmathparse{rand} (\x,\pgfmathresult)}}
不幸的是,上面的代码导致了一个错误
Undefined control sequence \pgffor@remember@once@code
。
我的问题是为什么这不起作用,以及保存\foreach
循环结果的最简单的解决方法是什么。
答案1
另一个答案提供了一个可行的解决方案,但其缺点是使用全局定义,除非真正必要,否则应该避免使用全局定义。pgf 附带了/.list
密钥处理程序,可以避免使用全局定义。
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[add point/.code={\pgfmathparse{rand}%
\edef\mypoints{\mypoints(#1,\pgfmathresult)}}]
\def\mypoints{} % initialize
\tikzset{add point/.list={0,0.2,...,5}}% loop without global definitions
\draw plot coordinates {\mypoints};
\end{tikzpicture}
\end{document}
答案2
您必须在外面进行循环\edef
:
\gdef\mypoints{} % initialize
\foreach\x in {0,0.1,...,1} {%
\pgfmathparse{rand}%
\xdef\mypoints{\mypoints(\x,\pgfmathresult)}%
}
因此在每个循环中你都会附加新的点。
使用上面的代码,我们可能会得到类似
(0,-0.5593)(0.1,0.51411)(0.20001,0.55302)
(0.30002,0.51347)(0.40002,-0.54858)(0.50003,-0.64978)
(0.60004,0.61548)(0.70004,-0.32903(0.80005,0.2993)
(0.90005,-0.38226)
(为了清晰起见,换行了)。嗯,这确实不是我们所期望的。
我们可以避免这种情况以及全局声明。
\documentclass{article}
\ExplSyntaxOn
\NewDocumentCommand{\fpforeach}{mmmm}
{% #1 = start, #2 = step, #3 = end, #4 = template
\fp_step_inline:nnnn { #1 } { #2 } { #3 } { #4 }
}
\NewDocumentCommand{\clearlist}{m}
{
\tl_clear_new:c { l_egreg_list_#1_tl }
}
\NewDocumentCommand{\addtolist}{smm}
{
\IfBooleanTF{#1}{\tl_put_right:cx}{\tl_put_right:cn} { l_egreg_list_#2_tl } { #3 }
}
\NewExpandableDocumentCommand{\uselist}{m}
{
\tl_use:c { l_egreg_list_#1_tl }
}
\ExplSyntaxOff
\clearlist{points} % initialize
\fpforeach{0}{0.1}{1}{%
\addtolist*{points}{(#1,\fpeval{round(2*rand()-1,4)}) }
}
\begin{document}
\raggedright
\uselist{points}
\end{document}
由于rand()
仅返回 0 到 1 之间的数字,但pgfmath
函数rand
返回从 -1 到 1 的数字,因此我使用2*rand()-1
。
可能的输出是
尾随空格仅用于排版目的。在的第四个参数中\fpforeach
,#1
代表循环中的当前值。
该\addtolist
命令只是简单地添加,但*
也会进行完全扩展。
请注意,x 坐标确实是从 0 到 1,因为l3fp
使用浮点十进制数(而不是像 那样将固定精度的二进制转换成十进制pgfmath
)。