
Basierend aufWipets Antwort, und mit dem gleichen Lerngeist über die Iterationsschleife „for“, ist es interessant herauszufinden, wie die vorgeschlagene „for-Schleife“ modularer sein könnte. Ich möchte als Argument die im obigen Beispiel vorgesehene iterierbare Liste übergeben.
\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}
Das Codeverhalten ist für meinen Zweck korrekt.
0 0 0
0 0 0
0 0 1.2
0 0 0.6
0 0.6*0.5 1.2+ 0.2
Diese Liste ist eine implizite Liste mit mehreren Variablen und Rechenoperationen in jeder Komponente. Die Hauptidee besteht also darin, die Liste als Makro zu übergeben, etwa so, \newcommand{\list}{0 0 0;0 0 0;0 0 \linkLength;0 0 \jointLength;0 {\jointLength*0.5} {\linkLength + \jointRadio}}
und sie als aufzurufen \for\i in \list
. Ich verstehe nicht, welche Änderungen in der Deklaration erforderlich sind, um dieses Verhalten zu erreichen. (Mir ist klar, dass dieses Verhalten mit der \foreach-Anweisung erreicht werden könnte, aber ich muss verstehen, wie das geht.)
Alle Ideen werden gerne entgegengenommen.
Antwort1
(Das Makro ist bereits für die -Umgebung in LaTeX 2e \list
definiert und wird verwendet . Daher wird im folgenden Beispiel stattdessen das Makro definiert und verwendet.)list
\MyList
Sie können die Angelegenheit beispielsweise ganz einfach so umgestalten, dass Sie nur das Makro erweitern, das die Liste enthält, und anschließend die Argumente austauschen.
Im folgenden Beispiel \expandafter
wird dazu verwendet, das Makro \MyList
(dessen Erweiterung die zu iterierende Liste ergibt) chronologisch zu erweitern, bevor \PassFirstToSecond
diese (in Klammern geschachtelte) Liste innerhalb der Anordnung, die durch den Token-Stream hinter der \for\i in
-Konstruktion gebildet wird, verschoben wird.
\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}
Sie können auch ein Makro wie verwenden, \romannumeral\Expandtimes
um die erforderliche Erweiterungsebene mit dem Argument anzugeben, das die Liste enthält:\romannumeral\Expandtimes
wird erklärt inWie erfahre ich die Anzahl der\expandafter
s beim Anhängen an ein csname-Makro ermitteln?:
\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}
Antwort2
\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}
Antwort3
Hier ist ein Code, den ich in meiner Freizeit entwickle. Speichern Sie den folgenden Code alsextforeach-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
Jetzt kann Ihr Dokument
\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}
Mit Hilfe von xfp
können wir sogar Ausdrücke auswerten.
Der format
Schlüssel richtet eine Vorlage für jedes Element in der durch Kommas getrennten Liste ein, die als erstes obligatorisches Argument angegeben ist. Hier #1 #2 #3
bedeutet dies, dass das Element aus Dingen wie
<subitem><space><subitem><space><subitem>
Das zweite obligatorische Argument ist Code, der die in der Vorlage festgelegten Argumente verwendet. Es gibt Abkürzungen single
(Standard, wenn nichts angegeben ist), double
die triple
für
format=#1
format=#1/#2
format=#1/#2/#3
jeweils.