\documentclass{article}
\usepackage{tikz}
\def\firstlist{0,1,2}
\def\secondlist{0,1,2}
\newcommand{\testa}{
\foreach \x/\y in {\firstlist/\secondlist} {
\draw(0,\x)--(1,\y);
}
}
\newcommand{\testb}{
\foreach \x/\y in {0/0,1/1,2/2} {
\draw(0,\x)--(1,\y);
}
}
\begin{document}
\begin{tikzpicture}
\testa
\end{tikzpicture}
\end{document}
如何才能使命令的输出\testa
等于\testb
命令的输出?
答案1
这是一个非常简单的解决方案:
\documentclass{article}
\usepackage{tikz}
\def\firstlist{0,1,2}
\def\secondlist{0,1,2}
\newcommand{\testa}{
\foreach \x [count=\c,evaluate=\c as \y using {{\secondlist}[\c-1]}] in \firstlist {
\draw(0,\x)--(1,\y);
}
}
\begin{document}
\begin{tikzpicture}
\testa
\end{tikzpicture}
\end{document}
定义新样式的扩展解决方案parallel foreach
。您可以使用多个并行列表:
\documentclass{standalone}
\usepackage{tikz}
\pgfset{
foreach/parallel foreach/.style args={#1in#2via#3}{evaluate=#3 as #1 using {{#2}[#3-1]}},
}
\def\firstlist{0,1,2,10,11}
\def\secondlist{0,1,2,10,11}
\def\thirdlist{1,2,10,11,0}
\newcommand{\testa}{
\foreach \x [count=\c,
parallel foreach=\y in \secondlist via \c,
parallel foreach=\z in \thirdlist via \c]
in \firstlist
{
\node[left] at (0,\x) {\x};
\draw(0,\x)--(1,\y);
\draw[red](0,\x)--(1,\z);
}
}
\begin{document}
\begin{tikzpicture}
\testa
\end{tikzpicture}
\end{document}
两种方法都使用大批pgfmath 的特点:它们将每个元素评估为一个数学公式。如果您想要字符串元素,请使用引号 ( "..."
)。
\documentclass[margin=1mm]{standalone}
\usepackage{tikz}
\pgfset{
foreach/parallel foreach/.style args={#1in#2via#3}{
evaluate=#3 as #1 using {{#2}[#3-1]}
},
}
\def\firstlist{0,1,2,10,11}
\def\secondlist{0,1,2,10,11}
\def\thirdlist{1,2,10,11,0}
\def\fourthlist{"label a","label b","label c","label $\delta$","label e"}
\newcommand{\testa}{
\foreach \x [count=\c,
parallel foreach=\y in \secondlist via \c,
parallel foreach=\z in \thirdlist via \c,
parallel foreach=\lab in \fourthlist via \c]
in \firstlist
{
\node[left] at (0,\x) {\lab};
\draw(0,\x)--(1,\y);
\draw[red](0,\x)--(1,\z);
}
}
\begin{document}
\begin{tikzpicture}
\testa
\end{tikzpicture}
\end{document}
答案2
你可以计算其中一个数组中有多少个元素,并将该数字用作 foreach 的限制。然后每次旋转都会访问数组的一个元素;
\documentclass[tikz]{standalone}
\def\firstlist{{0,1,2}} % <== Notice the double brace for array notation
\def\secondlist{{0,1,2}}
\newcommand{\testa}{
\pgfmathdim{\firstlist}%Get the number of elements in array
\foreach \x in {0,...,\numexpr\pgfmathresult-1\relax}{%array index starts from zero
\draw(0,{array(\firstlist,\x)})--(1,{array(\secondlist,\x)});
}
}
\newcommand{\testb}{
\foreach \x/\y in {0/0,1/1,2/2} {
\draw(0,\x)--(1,\y);
}
}
\begin{document}
\begin{tikzpicture}
\testa
\begin{scope}[shift={(2,0)}] %Test the result with \testb next to it
\testb
\end{scope}
\end{tikzpicture}
\end{document}
答案3
我不太确定你是否想这么做。;-)
\documentclass{article}
\usepackage{xparse}
\def\xforeach#1#{\xforeachaux{#1}}
\ExplSyntaxOn
\NewDocumentCommand{\xforeachaux}{mm}
{
\carlitos_xforeach:nn { #1 } { #2 }
}
\seq_new:N \l_carlitos_xf_first_seq
\seq_new:N \l_carlitos_xf_second_seq
\seq_new:N \l_carlitos_xf_list_seq
\cs_new_protected:Npn \carlitos_xforeach:nn #1 #2
{
\seq_clear:N \l_carlitos_xf_list_seq
\__carlitos_split:n { #2 }
\seq_mapthread_function:NNN
\l_carlitos_xf_first_seq
\l_carlitos_xf_second_seq
\__carlitos_xf_additem:nn
\__carlitos_xf_do:nx { #1 } { \seq_use:Nn \l_carlitos_xf_list_seq { , } }
}
\cs_new_protected:Npn \__carlitos_split:n #1
{
\__carlitos_split_aux:w #1 \q_stop
}
\cs_new_protected:Npn \__carlitos_split_aux:w #1/#2 \q_stop
{
\seq_set_split:Nno \l_carlitos_xf_first_seq { , } { #1 }
\seq_set_split:Nno \l_carlitos_xf_second_seq { , } { #2 }
}
\cs_new_protected:Npn \__carlitos_xf_additem:nn #1 #2
{
\seq_put_right:Nn \l_carlitos_xf_list_seq { #1/#2 }
}
\cs_new_protected:Npn \__carlitos_xf_do:nn #1 #2
{
\foreach #1 { #2 }
}
\cs_generate_variant:Nn \seq_set_split:Nnn { Nno }
\cs_generate_variant:Nn \__carlitos_xf_do:nn { nx }
\ExplSyntaxOff
\usepackage{tikz}
\def\firstlist{0,1,2}
\def\secondlist{0,1,2}
\newcommand{\testa}{
\xforeach \x/\y in {\firstlist/\secondlist} {
\draw(0,\x)--(1,\y);
}
}
\newcommand{\testb}{
\foreach \x/\y in {0/0,1/1,2/2} {
\draw(0,\x)--(1,\y);
}
}
\begin{document}
\begin{tikzpicture}
\testa
\end{tikzpicture}
\qquad
\begin{tikzpicture}
\testb
\end{tikzpicture}
\end{document}
一个完全不同的实现,你甚至不需要\x/\y
;它支持最多三个斜杠分隔的参数,可以是逗号分隔的列表(逗号前后的空格被忽略)或扩展为逗号分隔列表的宏。
foreach 循环中的每个循环都使用第二个参数执行,该参数使用#1
、#2
和#3
表示当前列表元素。循环次数由第一个列表决定。
如果给定的项目超过三个,可能应该提供更好的错误恢复,但这留作练习。
\documentclass{article}
\usepackage{xparse,tikz}
\ExplSyntaxOn
\NewDocumentCommand{\Xforeach}{mm}
{
\carlitos_Xforeach:nn { #1 } { #2 }
}
\seq_new:N \l__carlitos_Xf_input_seq
\seq_new:N \l__carlitos_Xf_output_seq
\seq_new:N \l__carlitos_Xf_lista_seq
\seq_new:N \l__carlitos_Xf_listb_seq
\seq_new:N \l__carlitos_Xf_listc_seq
\tl_new:N \l__carlitos_Xf_tmp_tl
\int_new:N \l__carlitos_Xf_cycle_int
\cs_new_protected:Npn \carlitos_Xforeach:nn #1 #2
{
\seq_set_split:Nnn \l__carlitos_Xf_input_seq { / } { #1 }
\seq_clear:N \l__carlitos_Xf_output_seq
\seq_map_inline:Nn \l__carlitos_Xf_input_seq
{
\seq_put_right:No \l__carlitos_Xf_output_seq { ##1 }
}
\int_case:nnF { \seq_count:N \l__carlitos_Xf_input_seq }
{
{ 1 } { \__carlitos_Xf_one:n { #2 } }
{ 2 } { \__carlitos_Xf_two:n { #2 } }
{ 3 } { \__carlitos_Xf_three:n { #2 } }
}
{
Only~one,~two~or~three!
}
}
\cs_new_protected:Npn \__carlitos_Xf_one:n #1
{
\seq_pop_left:NN \l__carlitos_Xf_output_seq \l__carlitos_Xf_tmp_tl
\seq_set_split:NnV \l__carlitos_Xf_first_seq { , } \l__carlitos_Xf_tmp_tl
\cs_set_protected:Npn \__carlitos_Xf_loop:n ##1 { #1 }
\cs_generate_variant:Nn \__carlitos_Xf_loop:n { x }
\int_zero:N \l__carlitos_Xf_cycle_int
\seq_map_inline:Nn \l__carlitos_Xf_first_seq
{
\int_incr:N \l__carlitos_Xf_cycle_int
\__carlitos_Xf_loop:x { \seq_item:Nn \l__carlitos_Xf_first_seq { \l__carlitos_Xf_cycle_int } }
}
}
\cs_new_protected:Npn \__carlitos_Xf_two:n #1
{
\seq_pop_left:NN \l__carlitos_Xf_output_seq \l__carlitos_Xf_tmp_tl
\seq_set_split:NnV \l__carlitos_Xf_first_seq { , } \l__carlitos_Xf_tmp_tl
\seq_pop_left:NN \l__carlitos_Xf_output_seq \l__carlitos_Xf_tmp_tl
\seq_set_split:NnV \l__carlitos_Xf_second_seq { , } \l__carlitos_Xf_tmp_tl
\cs_set_protected:Npn \__carlitos_Xf_loop:nn ##1 ##2 { #1 }
\cs_generate_variant:Nn \__carlitos_Xf_loop:nn { xx }
\int_zero:N \l__carlitos_Xf_cycle_int
\seq_map_inline:Nn \l__carlitos_Xf_first_seq
{
\int_incr:N \l__carlitos_Xf_cycle_int
\__carlitos_Xf_loop:xx
{ \seq_item:Nn \l__carlitos_Xf_first_seq { \l__carlitos_Xf_cycle_int } }
{ \seq_item:Nn \l__carlitos_Xf_second_seq { \l__carlitos_Xf_cycle_int } }
}
}
\cs_new_protected:Npn \__carlitos_Xf_three:n #1
{
\seq_pop_left:NN \l__carlitos_Xf_output_seq \l__carlitos_Xf_tmp_tl
\seq_set_split:NnV \l__carlitos_Xf_first_seq { , } \l__carlitos_Xf_tmp_tl
\seq_pop_left:NN \l__carlitos_Xf_output_seq \l__carlitos_Xf_tmp_tl
\seq_set_split:NnV \l__carlitos_Xf_second_seq { , } \l__carlitos_Xf_tmp_tl
\seq_pop_left:NN \l__carlitos_Xf_output_seq \l__carlitos_Xf_tmp_tl
\seq_set_split:NnV \l__carlitos_Xf_third_seq { , } \l__carlitos_Xf_tmp_tl
\cs_set_protected:Npn \__carlitos_Xf_loop:nnn ##1 ##2 ##3 { #1 }
\cs_generate_variant:Nn \__carlitos_Xf_loop:nnn { xxx }
\int_zero:N \l__carlitos_Xf_cycle_int
\seq_map_inline:Nn \l__carlitos_Xf_first_seq
{
\int_incr:N \l__carlitos_Xf_cycle_int
\__carlitos_Xf_loop:xxx
{ \seq_item:Nn \l__carlitos_Xf_first_seq { \l__carlitos_Xf_cycle_int } }
{ \seq_item:Nn \l__carlitos_Xf_second_seq { \l__carlitos_Xf_cycle_int } }
{ \seq_item:Nn \l__carlitos_Xf_third_seq { \l__carlitos_Xf_cycle_int } }
}
}
\ExplSyntaxOff
\begin{document}
\def\firstlist{0,1,2}
\def\secondlist{0,1,2}
\def\thirdlist{a,b,c}
\Xforeach{\firstlist}{--#1-- }
\bigskip
\begin{tikzpicture}
\Xforeach{\firstlist/\secondlist}{\draw(0,#1)--(1,#2);}
\end{tikzpicture}\qquad
\begin{tikzpicture}
\Xforeach{0,1,2/\secondlist}{\draw(0,#1)--(1,#2);}
\end{tikzpicture}
\bigskip
\Xforeach{\firstlist/\secondlist/\thirdlist}{#1/#2/#3 }
\Xforeach{\firstlist/\secondlist/\thirdlist}{#1/#2/#3 }
\Xforeach{\firstlist/0,1,2/a,b,c}{#1/#2/#3 }
\end{document}
答案4
你总是可以“推出自己的”解决方案,但要使它看起来这么好,需要做大量的工作\foreach
:
\documentclass[tikz,border=5]{standalone}
\makeatletter
\def\attxt{@}
\long\def\frch#1#2#3{\long\def\frchaction##1##2{#3}%
\def\lsta{}\def\lstb{}%
\edef\lst{#1,@,/#2,@,}\expandafter\@frch\lst\@}
\def\@frch#1,#2/#3,#4\@{%
\def\tmpa{#1}\def\tmpb{#3}%
\ifx\tmpa\attxt%
\ifx\tmpb\attxt%
\else%
\def\lstb{#3}\frchaction{\lsta}{#3}\@frch @,/#4,\@%
\fi%
\else%
\ifx\tmpb\attxt%
\def\lsta{#1}\frchaction{#1}{\lstb}\@frch#2/@,\@%
\else%
\def\lsta{#1}\def\lstb{#3}\frchaction{#1}{#3}\@frch#2/#4\@%
\fi%
\fi}
\begin{document}
\begin{tikzpicture}
\frch{0,1,2}{0,1,2}{ \draw (0,#1) -- (1,#2); }
\frch{0,1,2}{0,1,2,3,4,5}{ \draw (2,#1) -- (3,#2); }
\frch{0,1,2,3,4,5}{0,1,2}{ \draw (4,#1) -- (5,#2); }
\end{tikzpicture}
\end{document}