我想定义一个命令,返回一个或另一个列表,作为用括号括起来的列表,在我的真实文档而不是这个 MWE 中,我可以将其用作其他内容的参数(即,在 TikZ 结构中要迭代的列表\foreach
)。
以下不是工作!
\documentclass{article}
\usepackage{ifthen}
\usepackage{tikz}
\newcommand{\whichlist}[1]{%
\ifthenelse{#1=1}{{1,2,3}}%
{{4,5}}
}
\begin{document}
I want to get \verb!{1,2,3}! but I get:
\whichlist{1}
I want to get \verb!{4,5}! but I get:
\whichlist{2}
Fanciful usage for MWE purposes is:
\begin{tikzpicture}
%\foreach \x in {\whichlist{1}} { \draw (0,0)--(\x,\x); }; % this gives error
% Preceding, uncommented, should give same result as this:
\foreach \x in {1,2,3}{ \draw (0,0)--(\x,\x*\x);}
\end{tikzpicture}
\end{document}
答案1
你做得到{1,2,3}
,但括号是组分隔符,因此不打印任何内容。不,你的尝试不能工作,因为\whichlist{1}
不是列表,而是说明打印它。
您可以使用\foreach \x in \foo {...}
provided\foo
宏,该宏在单个扩展步骤后扩展为列表:因此,如果您这样做
\newcommand{\foo}{1,2,3}
然后
\foreach \x in \foo {...}
其工作原理与
\foreach \x in {1,2,3}{...}
经过一个扩展步骤后,您\whichlist{1}
并没有得到一个列表。
您可以这样做:
\documentclass{article}
\usepackage{tikz}
\ExplSyntaxOn
\NewDocumentCommand{\preparelists}{O{default}m}
{
\seq_clear_new:c { l_murray_lists_#1_seq }
\tl_map_inline:nn { #2 }
{
\seq_put_right:cn { l_murray_lists_#1_seq } { ##1 }
}
}
\NewExpandableDocumentCommand{\fetchlist}{O{default}m}
{
{ \seq_item:cn { l_murray_lists_#1_seq } { #2 } }
}
\ExplSyntaxOff
\preparelists{
{1,2,3}
{a,b,c,d}
}
\begin{document}
\begin{tikzpicture}
\expanded{\unexpanded{\foreach \x in }\fetchlist{1}} {
\draw (0,0)--(\x,\x*\x/2);
}
\end{tikzpicture}
\end{document}
但当然那东西相当不方便。这里有一个不太麻烦的方法,但请注意 周围的括号\fetchlist{1}
。
\documentclass{article}
\usepackage{tikz}
\ExplSyntaxOn
\NewDocumentCommand{\preparelists}{O{default}m}
{
\seq_clear_new:c { l_murray_lists_#1_seq }
\tl_map_inline:nn { #2 }
{
\seq_put_right:cn { l_murray_lists_#1_seq } { ##1 }
}
}
\NewExpandableDocumentCommand{\fetchlist}{O{default}m}
{
{ \seq_item:cn { l_murray_lists_#1_seq } { #2 } }
}
\cs_new_protected:Npn \expandedforeach #1 in #2
{
\use:e { \exp_not:n { \foreach #1~in~ } #2 }
}
\ExplSyntaxOff
\preparelists{
{1,2,3}
{a,b,c,d}
}
\begin{document}
\begin{tikzpicture}
\expandedforeach \x in {\fetchlist{1}} {
\draw (0,0)--(\x,\x*\x/2);
}
\end{tikzpicture}
\end{document}
你可以定义任意数量的列表,只要给它们命名即可:例如,如果你想命名foo
这个列表,你可以这样做
\documentclass{article}
\usepackage{tikz}
\ExplSyntaxOn
\NewDocumentCommand{\preparelists}{O{default}m}
{
\seq_clear_new:c { l_murray_lists_#1_seq }
\tl_map_inline:nn { #2 }
{
\seq_put_right:cn { l_murray_lists_#1_seq } { ##1 }
}
}
\NewExpandableDocumentCommand{\fetchlist}{O{default}m}
{
{ \seq_item:cn { l_murray_lists_#1_seq } { #2 } }
}
\cs_new_protected:Npn \expandedforeach #1 in #2
{
\use:e { \exp_not:n { \foreach #1~in~ } #2 }
}
\ExplSyntaxOff
\preparelists[foo]{
{1,2,3}
{a,b,c,d}
}
\begin{document}
\begin{tikzpicture}
\expandedforeach \x in {\fetchlist[foo]{1}} {
\draw (0,0)--(\x,\x*\x/2);
}
\end{tikzpicture}
\end{document}
默认名称为default
。
答案2
问题在于\foreach
TikZ 的参数语法有些不切实际,因此您必须使用\expanded
才能获取宏的结果列表。您可以\myforeach
按如下方式定义宏:
\documentclass{article}
\usepackage{tikz}
\def\listlist#1{\ifcase#1 \or
{1,2,3}\or % 1
{4,5}\or % 2
{6,7,8}\fi % 3
}
\def\myforeach#1inlist#2{\expanded{\noexpand\foreach\noexpand#1 in \listlist{#2}}}
\begin{document}
\begin{tikzpicture}
\myforeach \x inlist 1 {
\draw (0,0)--(\x,\x*\x/2);
}
\end{tikzpicture}
\end{document}
当然,您不需要任何\ExplSyntaxOn
,这里只使用 TeX 原语。