TikZ 是否提供了一种合理的原生/简洁的方式来表达“如果循环变量是该集合的一个元素,那么......”?
评论。 我要求的一个例子是伪代码
\pgfmathparse{\index in {0,2,4,6,8}}
当然,当且仅当 \index==0 或 \index==2 或 \index==4 或 \index==6 或 \index==8 在其他非伪代码中时,其结果才应为布尔值 1
\documentclass{article}
\usepackage{tikz}
\usepackage{ifthen}
\begin{document}
\begin{tikzpicture}
\foreach \index in {0,1,...,101}{
\ifthenelse{
\pgfmathparse{\index in {0,2,4,6,8}} % <-
}{
\node (v\index) at (\index cm,\index cm) {$\index$};
}{
};
}
\end{tikzpicture}
\end{document}
编写一个循环,将 {0,2,4,6,8} 直接硬连线为其循环变量的范围,这对我来说不是一个选择,因为上面只是我需要这个应用程序的一个小说明性示例,它有一个大的外循环,然后需要几个形式为“如果循环变量在这个集合中,则执行此操作”的 if 条件,其中出现了几个完全不同的“这个集合”。
简而言之,我需要根据形式为“循环变量是否在指定集合中”的查询的布尔值来控制循环。
当然,你可以写一个很长的逻辑或相等测试,分别比较
\index
0、2、4、6、8。如果能写得更简洁一些就更好了。我在手册里没找到。
答案1
这是一个简单的解决方案。但您必须先声明并命名您的集合。
\documentclass{article}
\usepackage{etoolbox}
\usepackage{tikz}
\tikzset{
def set elem/.code 2 args={\csdef{@sets@#1@#2}{}{}},
def set/.style 2 args={
def elem in@#1/.style={def set elem={#1}{##1}},
def elem in@#1/.list={#2},
}
}
\def\ifinset#1#2{\ifcsdef{@sets@#1@#2}}
\begin{document}
\tikzset{def set={myset}{2,4,6}}
\foreach \myval in {1,...,10}{
\ifinset{myset}{\myval}{\myval{} in set\par}{\myval{} not in set\par}
}
\end{document}
结果:
1 not in set
2 in set
3 not in set
4 in set
5 not in set
6 in set
7 not in set
8 not in set
9 not in set
10 not in set
答案2
TikZ 不提供某项是否在列表中的测试。使用 PGF 宏也无法实现此测试,因为\foreach
它不完全可扩展。
这是一个使用 Lua 来实现这个功能的方法。
\documentclass{article}
\usepackage{tikz}
\usepackage{ifthen}
\directlua{
function has_value(t,v)
for _,e in ipairs(t) do
if e == v then
tex.sprint("\noexpand\\boolean{true}")
return
end
end
tex.sprint("\noexpand\\boolean{false}")
end
}
\def\ifinset#1#2{\directlua{has_value({#1},#2)}}
\begin{document}
\begin{tikzpicture}
\foreach \index in {0,1,...,101}{
\ifthenelse{
\ifinset{0,2,4,6,8}{\index}
}{
\node (v\index) at (\index cm,\index cm) {$\index$};
}{
};
}
\end{tikzpicture}
\end{document}
如果您不介意循环测试集,那么在 TikZ 中也可以轻松实现。
\documentclass{article}
\usepackage{tikz}
\usepackage{ifthen}
\begin{document}
\begin{tikzpicture}
\foreach \index in {0,1,...,101}{
\foreach \test in {0,2,4,6,8} {
\ifthenelse{\equal{\index}{\test}}{
\node (v\index) at (\index cm,\index cm) {$\index$};
}{
% false case
}
}
}
\end{tikzpicture}
\end{document}
答案3
您可以在 的帮助下做到这一点expl3
; 的第二个参数\IsInTF
也可以是扩展为列表的宏。
\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\IsInTF}{mmmm}
{
\clist_if_in:xxTF { #2 } { #1 } { #3 } { #4 }
}
\prg_generate_conditional_variant:Nnn \clist_if_in:nn { xx } { T,F,TF }
\ExplSyntaxOff
\begin{document}
\begin{tikzpicture}
\foreach \index in {0,1,...,101}{
\IsInTF{\index}{0,2,4,8} % <-
{\node (v\index) at (\index cm,\index cm) {$\index$};}
{};
}
\end{tikzpicture}
\end{document}
答案4
如果您想使用他的代码来定义新命令,元素将仅添加到先前命令的集合中。因此,需要在使用该集合后立即再次删除元素。这可以以类似的方式完成,通过使用\cslet
并将元素设置为\undefined
。这是一个完整的 MWE:
\documentclass{article}
\usepackage{etoolbox}
\usepackage{tikz}
\tikzset{
def set elem/.code 2 args={\csdef{@sets@#1@#2}{}{}},
def set/.style 2 args={
def elem in@#1/.style={def set elem={#1}{##1}},
def elem in@#1/.list={#2},
},
% these five lines are new to undefine elements:
undef set elem/.code 2 args={\cslet{@sets@#1@#2}{\undefined}},
undef set/.style 2 args={
undef elem in@#1/.style={undef set elem={#1}{##1}},
undef elem in@#1/.list={#2},
}
}
\def\ifinset#1#2{\ifcsdef{@sets@#1@#2}}
\newcommand{\mycommand}[1]{%
\tikzset{def set={myset}{#1}}
\begin{tikzpicture}[
every node/.style={minimum size=5mm, anchor=south west, inner sep=0pt},
scale=0.5
]
\foreach \myval in {1,...,20}{
\ifinset{myset}{\myval}{
\node [white, fill=green, font=\sffamily\bfseries] at (\myval, 0) {\myval};
}{
\fill [black] (\myval, 0) rectangle ++(1, 1);
}
}
\end{tikzpicture}
\tikzset{undef set={myset}{#1}} %<< new: required to remove the numbers again
}
\begin{document}
\thispagestyle{empty}
\mycommand{2,4,6,8,10,12,14,16,18,20}\par
\mycommand{3,6,9,12,15,18}\par
\mycommand{4,8,12,16,20}\par
\mycommand{5,10,15,20}\par
\mycommand{6,12,18}\par
\mycommand{7,14}\par
\mycommand{8,16}\par
\mycommand{9,18}\par
\mycommand{10,20}\par
\end{document}
相反,当您没有取消定义元素(注释掉\tikzset{undef set={myset}{#1}}
)时,结果如下所示: