![模块化宏列表结构来迭代它](https://linux22.com/image/391364/%E6%A8%A1%E5%9D%97%E5%8C%96%E5%AE%8F%E5%88%97%E8%A1%A8%E7%BB%93%E6%9E%84%E6%9D%A5%E8%BF%AD%E4%BB%A3%E5%AE%83.png)
根据Wipet 的回答,并本着同样的学习精神,关于迭代循环“for”,有趣的是发现建议的“for 循环”如何更加模块化。我想将上例中提到的可迭代列表作为参数传递。
\documentclass[a4paper]{article}
\usepackage{pst-solides3d}
%%% FOR LOOP %%%
\makeatletter
\long\def\for#1in#2#3{\expandafter\def\csname b:\string#1\endcsname{#3}%
\@forinA#1#2;}
\long\def\@forinA#1#2;{\ifx#2\else
\def#1{#2}\csname b:\string#1\endcsname \expandafter\@forinA\expandafter#1\fi}
%%%%%%%%%%%%%%%%%%
\makeatother
%% Variables%%
\pgfmathparse{1.2}\edef\linkLength{\pgfmathresult}
\pgfmathparse{0.2}\edef\jointRadio{\pgfmathresult}
\pgfmathparse{0.6}\edef\jointLength{\pgfmathresult}
\newcommand{\iterating}{
%%% point's structure %%%
\for\i in {%
0 0 0;% N°0
0 0 0;% N°1
0 0 \linkLength;% N°2
0 0 \jointLength;% N°3
0 {\jointLength*0.5} {\linkLength + \jointRadio};% N°4
}
{%
\i\par
%... call to several macros
}%
}
\begin{document}
\iterating
\end{document}
代码行为对于我的目的来说是正确的。
0 0 0
0 0 0
0 0 1.2
0 0 0.6
0 0.6*0.5 1.2+ 0.2
此列表是一个隐式列表,每个组件中都有几个变量和算术运算。因此,主要思想是将列表作为宏传递,类似于\newcommand{\list}{0 0 0;0 0 0;0 0 \linkLength;0 0 \jointLength;0 {\jointLength*0.5} {\linkLength + \jointRadio}}
并将其称为\for\i in \list
。我不明白在 for 声明中需要进行哪些修改才能实现此行为。(我意识到可以使用 \foreach 语句实现此行为,但我需要了解如何实现)
任何想法都将受到欢迎。
答案1
(该宏\list
已list
在 LaTeX 2e 中的 -environment 中定义并使用。
因此,在下面的示例中,\MyList
定义并使用该宏。)
例如,您可以轻松地将问题转变为扩展包含列表的宏并然后交换参数的问题。
使用下面的例子,\expandafter
用于按\MyList
时间顺序扩展宏(其扩展产生要迭代的列表),然后通过\PassFirstToSecond
移动该列表(嵌套在括号中)在由构造后面的标记流形成的排列中移动\for\i in
。
\documentclass[a4paper]{article}
\usepackage{pst-solides3d}
%%% FOR LOOP %%%
\makeatletter
\long\def\for#1in#2#3{\expandafter\def\csname b:\string#1\endcsname{#3}%
\@forinA#1#2;}
\long\def\@forinA#1#2;{\ifx#2\else
\def#1{#2}\csname b:\string#1\endcsname \expandafter\@forinA\expandafter#1\fi}
%%%%%%%%%%%%%%%%%%
\makeatother
%% Variables%%
\pgfmathparse{1.2}\edef\linkLength{\pgfmathresult}
\pgfmathparse{0.2}\edef\jointRadio{\pgfmathresult}
\pgfmathparse{0.6}\edef\jointLength{\pgfmathresult}
\newcommand{\iterating}{%%%%%%%%%%%%%
%%% point's structure %%%
\for\i in {%
0 0 0;% N°0
0 0 0;% N°1
0 0 \linkLength;% N°2
0 0 \jointLength;% N°3
0 {\jointLength*0.5} {\linkLength + \jointRadio};% N°4
}
{%
\i\par
%... call to several macros
}%
}
\newcommand\PassFirstToSecond[2]{#2{#1}}
\newcommand\MyList{%
0 0 0;% N°0
0 0 0;% N°1
0 0 \linkLength;% N°2
0 0 \jointLength;% N°3
0 {\jointLength*0.5} {\linkLength + \jointRadio};% N°4
}%
\begin{document}
\noindent\verb|\iterating| yields:
\iterating
\bigskip
\noindent\verb|\expandafter\PassFirstToSecond\expandafter{\MyList}{\for\i in }{\i\par}| yields:
\expandafter\PassFirstToSecond\expandafter{\MyList}{\for\i in }{\i\par}%
\bigskip
\noindent You can also do another kind of \verb|\expandafter|-orgy:
\bigskip
\noindent\verb|\expandafter\for\expandafter\i\expandafter i\expandafter n\expandafter{\MyList}{\i\par}| yields:
\expandafter\for\expandafter\i\expandafter i\expandafter n\expandafter{\MyList}{\i\par}%
\end{document}
您还可以使用类似的宏\romannumeral\Expandtimes
来指定所需的扩展级别,其中包含列表的参数,\romannumeral\Expandtimes
解释如下\expandafter
在附加到 csname 宏时,如何知道 s 的数量?:
\documentclass[a4paper]{article}
\usepackage{pst-solides3d}
%%% FOR LOOP %%%
\makeatletter
%
\newcommand\exchange[2]{#2#1}%
% A check is needed for finding out if an argument is catcode-11-"d" while there are only
% the possibilities that the argument is either a single catcode-11-"d"
% or a single catcode-12-"m":
\def\innerdfork#1d#2#3dd{#2}%
\def\dfork#1{\innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd}%
% By means of \romannumeral create as many catcode-12-characters m as expansion-steps are to take place.
% Then by means of recursion for each of these m double the amount of `\expandafter`-tokens and
% add one `\expandafter`-token within \innerExp's first argument.
\def\Expandtimes#1{0\expandafter\innerExp\expandafter{\expandafter}\romannumeral\number\number#1 000d}
\def\innerExp#1#2{\dfork{#2}{#1 }{\innerExp{#1#1\expandafter}}}
\long\def\for#1in #2-level-expansion of #3#4{%
\expandafter\def\csname b:\string#1\endcsname{#4}%
\expandafter\exchange\expandafter{\romannumeral\Expandtimes{#2}#3;}{\@forinA#1}%
}
\long\def\@forinA#1#2;{\ifx#2\else
\def#1{#2}\csname b:\string#1\endcsname \expandafter\@forinA\expandafter#1\fi}
%%%%%%%%%%%%%%%%%%
\makeatother
%% Variables%%
\pgfmathparse{1.2}\edef\linkLength{\pgfmathresult}
\pgfmathparse{0.2}\edef\jointRadio{\pgfmathresult}
\pgfmathparse{0.6}\edef\jointLength{\pgfmathresult}
\newcommand\MyList{%
0 0 0;%
0 0 0;%
0 0 \linkLength;%
0 0 \jointLength;%
0 {\jointLength*0.5} {\linkLength + \jointRadio};%
}%
\newcommand\MyOuterListContainer{\MyInnerListContainer}
\newcommand\MyInnerListContainer{\MyList}
\begin{document}
\begingroup
\topsep=0ex \partopsep=0ex
\begin{verbatim}
\for\i in 0-level-expansion of {%
0 0 0;%
0 0 0;%
0 0 \linkLength;%
0 0 \jointLength;%
0 {\jointLength*0.5} {\linkLength + \jointRadio};%
}{\i\par}%
\end{verbatim}%
\smallskip
\endgroup
\noindent yields:
\for\i in 0-level-expansion of {%
0 0 0;%
0 0 0;%
0 0 \linkLength;%
0 0 \jointLength;%
0 {\jointLength*0.5} {\linkLength + \jointRadio};%
}{\i\par}%
\bigskip
\noindent\verb|\for\i in 1-level-expansion of {\MyList}{\i\par}| yields:
\for\i in 1-level-expansion of {\MyList}{\i\par}
\bigskip
\noindent\verb|\for\i in 3-level-expansion of {\MyOuterListContainer}{\i\par}| yields:
\for\i in 3-level-expansion of {\MyOuterListContainer}{\i\par}
\end{document}
答案2
\documentclass[a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage{pst-solides3d}
%% Variables%%
\pgfmathparse{1.2}\edef\linkLength{\pgfmathresult}
\pgfmathparse{0.2}\edef\jointRadio{\pgfmathresult}
\pgfmathparse{0.6}\edef\jointLength{\pgfmathresult}
\newcommand\itlist{
0 0 0;% N°0
0 0 0;% N°1
0 0 \linkLength;% N°2
0 0 \jointLength;% N°3
0 {\jointLength*0.5} {\linkLength + \jointRadio};% N°4
}
\usepackage{listofitems}
\begin{document}
\setsepchar{;/ }
\ignoreemptyitems
\readlist*\mylist{\itlist}
Iterate by row:
\foreachitem\x\in\mylist[]{\par%
\fbox{\x}
}
Third item on 5th row (the actual tokens):\\
\detokenize\expandafter\expandafter\expandafter{\mylist[5,3]}\\
which expands to \mylist[5,3]
1st, 3rd items on 3rd row, in a box is \fbox{\mylist[3,2],\mylist[3,3]}
Now to iterate on each item:
\foreachitem\x\in\mylist{\par%
\foreachitem\y\in\mylist[\xcnt]{%
\fbox{\y}
}}
\end{document}
答案3
以下是我为休闲而开发的一些代码。将以下代码保存为extforeach-code.tex
% extforeach-code.tex
\ExplSyntaxOn
\providecommand\fpeval{\fp_eval:n}
\NewDocumentCommand{\nforeach}{ m +m }
{
\tl_clear:N \l__manual_nforeach_type_tl
\keys_set:nn { manual/nforeach }
{
type=integers,start = 1, step = 1, end = 0,
}
\keys_set:nn { manual/nforeach } { #1 }
\__manual_nforeach_exec:n { #2 }
}
\int_new:N \g__manual_foreach_map_int
\int_new:N \g__manual_fp_map_int
\tl_new:N \l__manual_nforeach_type_tl
\keys_define:nn { manual/nforeach }
{
type .choice:,
type .value_required:n = true,
type/integers .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { integers },
type/fp .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { fp },
type/alph .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { alph },
type/Alph .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { Alph },
start .tl_set:N = \l__manual_nforeach_start_tl,
step .tl_set:N = \l__manual_nforeach_step_tl,
end .tl_set:N = \l__manual_nforeach_end_tl,
}
\cs_new_protected:Nn \__manual_nforeach_exec:n
{
\int_gincr:N \g__manual_foreach_map_int
\str_case:Vn \l__manual_nforeach_type_tl
{
{integers}{\__manual_nforeach_exec_integers:n { #1 }}
{fp} {\__manual_nforeach_exec_fp:n { #1 }}
{alph} {\__manual_nforeach_exec_alph:Nn \int_to_alph:n { #1 }}
{Alph} {\__manual_nforeach_exec_alph:Nn \int_to_Alph:n { #1 }}
}
\int_gdecr:N \g__manual_foreach_map_int
}
\cs_generate_variant:Nn \str_case:nn { V }
\cs_new_protected:Nn \__manual_nforeach_exec_integers:n
{
\int_step_inline:nnnn
{ \l__manual_nforeach_start_tl }
{ \l__manual_nforeach_step_tl }
{ \l__manual_nforeach_end_tl }
{ #1 }
}
\cs_new_protected:Nn \__manual_nforeach_exec_alph:Nn
{
\cs_set:cn { __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :n } { #2 }
\cs_generate_variant:cn
{ __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :n }
{ f }
\int_step_inline:nnnn
{ \int_from_alph:f { \l__manual_nforeach_start_tl } }
{ \l__manual_nforeach_step_tl }
{ \int_from_alph:f { \l__manual_nforeach_end_tl } }
{
\use:c { __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :f }
{ #1 { ##1 } }
}
}
\cs_generate_variant:Nn \cs_generate_variant:Nn { c }
\cs_generate_variant:Nn \int_from_alph:n { f }
\cs_new_protected:Nn \__manual_nforeach_exec_fp:n
{
\fp_step_inline:nnnn
{ \l__manual_nforeach_start_tl }
{ \l__manual_nforeach_step_tl }
{ \l__manual_nforeach_end_tl }
{ #1 }
}
\NewDocumentCommand{\lforeach}{ s O{} m +m }
{
\IfBooleanTF{#1}
{
\manual_lforeach:non { #2 } { #3 } { #4 }
}
{
\manual_lforeach:nnn { #2 } { #3 } { #4 }
}
}
\cs_new_protected:Nn \manual_lforeach:nnn
{
\keys_set:nn { manual/lforeach } { single }
\keys_set:nn { manual/lforeach } { #1 }
\clist_set:Nn \l__manual_lforeach_list_clist { #2 }
\int_gincr:N \g__manual_foreach_map_int
\__manual_lforeach_define:n { #3 }
\clist_map_inline:Nn \l__manual_lforeach_list_clist
{
\use:c { __manual_lforeach_ \int_use:N \g__manual_foreach_map_int _action:w } ##1 \q_stop
}
\int_gdecr:N \g__manual_foreach_map_int
}
\cs_generate_variant:Nn \manual_lforeach:nnn { no }
\cs_new_protected:Nn \__manual_lforeach_define:n
{
\exp_last_unbraced:NcV
\cs_set:Npn
{ __manual_lforeach_ \int_use:N \g__manual_foreach_map_int _action:w }
\l__manual_lforeach_format_tl
\q_stop
{#1}
}
\keys_define:nn { manual/lforeach }
{
format .tl_set:N = \l__manual_lforeach_format_tl,
single .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1 },
double .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1/##2 },
triple .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1/##2/##3 },
}
\ExplSyntaxOff
现在您的文档可以
\documentclass{article}
\usepackage{xparse,xfp}
\input{extforeach-code.tex}
\newcommand\linkLength{1.2}
\newcommand\jointRadio{0.2}
\newcommand\jointLength{0.6}
\newcounter{lines}
\begin{document}
\lforeach[format=#1 #2 #3]{
0 0 0, % N°0
0 0 0, % N°1
0 0 \linkLength, % N°2
0 0 \jointLength, % N°3
0 {\jointLength*0.5} {\linkLength + \jointRadio}, % N°4
}
{%
\stepcounter{lines}Line \thelines\ is \fpeval{#1}~\fpeval{#2}~\fpeval{#3}\par
}
\end{document}
借助它xfp
我们甚至可以评估表达式。
该format
键为第一个强制参数给出的逗号分隔列表中的每个项目设置一个模板,这里的#1 #2 #3
意思是该项目将由以下内容组成
<subitem><space><subitem><space><subitem>
第二个强制参数是使用模板中设置的参数的代码。有缩写single
(如果未指定,则为默认缩写),double
代表triple
format=#1
format=#1/#2
format=#1/#2/#3
分别。