Was ist der Unterschied zwischen den verschiedenen Methoden zur Erzeugung von For-Schleifen?

Was ist der Unterschied zwischen den verschiedenen Methoden zur Erzeugung von For-Schleifen?

Ich habe mich über die verschiedenen verfügbaren Methoden zum Durchlaufen einer durch Kommas getrennten Liste und dergleichen gewundert. Insbesondere habe ich mich über ihre verschiedenen Stärken und Schwächen gewundert. Mit anderen Worten, ich habe mich über Dinge wie Folgendes gewundert (aber nicht nur auf diese Liste beschränkt):

  1. ob sie erweiterbar sind oder nicht,
  2. wie sie mit Leergut umgehen,
  3. wie mit überflüssigen Leerzeichen am Anfang und Ende umgegangen wird
  4. \defob Sie / verwenden können \edefoder müssen, \gdefum \xdefInformationen innerhalb der Schleife für die spätere Verwendung zu speichern.

Hier ist eine Liste der mir bekannten Schleifenmethoden, ohne bestimmte Reihenfolge. In der folgenden Liste \current@itemist ein Makro mit einem Argument dargestellt, um das aktuelle Element in der Iteration zu formatieren.

Verwenden von Befehlen aus 2ekernal:

%% \@for
\def\@for@myloop#1{%%
  \@for \x:=#1 \do{\current@item \x}}

%% \@tfor (not a comma separated list--probably shouldn't be here)
\def\@tfor@myloop#1{%%
  \@tfor \x:=#1 \do{\if,\x\relax\else\current@item \x\fi}}

etoolboxPaket verwenden

%% `etoolbox`:  need to be careful whether passed a macro:
%%  in that case expansion may be necessary to that the 
%%  delimiters are visible to `\forcsvlist`
\def\etoolbox@myloop#1{%%
  \expandafter\forcsvlist
  \expandafter\current@item
  \expandafter{#1}}

pgfforPaket verwenden

%% pgffor
\def\pgffor@myloop#1{%%
  \foreach \x in {#1} {\current@item \x}}

Eine Homebrew-Methode:

%% version a la `ae`
\def\@ae@myloop#1,#2\@nil{%%
  \current@item{#1}%%
  \expandafter\ifx\expandafter\relax\detokenize{#2}\relax\else
    \@ae@myloop#2\@nil
   \fi
}
\def\ae@myloop#1{%%
  \@ae@myloop#1,\@nil
}

Dann gibt es auch noch die verschiedenen expl3Methoden wie (davon gibt es ziemlich viele, diese Liste ist also kaum erschöpfend):

\tl_map_inline:nn
\tl_map_function:Nn
\clist_map_inline:Nn
\seq_map_inline:Nn

Hier ist ein MWE, das die Ergebnisse von jedem davon veranschaulicht (einschließlich einer LaTeX3-Version):

\documentclass{article}
\usepackage[margin=0.5in,paperheight=15in]{geometry}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{pgffor}
\usepackage{enumitem}
\makeatletter

\def\my@item@count{0}
\def\step@my@counter{\xdef\my@item@count{\number\numexpr\my@item@count+1\relax}}
%% \rules to emphasize how spaces are seen and treated!
\def\current@item#1{\step@my@counter\item \rule{0.4pt}{2ex}#1\rule{0.4pt}{2ex}}

%% `etoolbox`
\def\etoolbox@myloop#1{%%
  \forcsvlist \current@item {#1}}
  %% but if passed a macro, then it  first needs to be expanded so the delimiters are visible to `\forcsvlist`.  You'll need to write
  %% \expandafter\forcsvlist \expandafter\current@item \expandafter{#1}}

%% \@for
\def\@for@myloop#1{%%
  \@for \x:=#1 \do{\current@item \x}}

%% \@tfor
\def\@tfor@myloop#1{%%
  \@tfor \x:=#1 \do{\current@item \x}}

%% pgffor
\def\pgffor@myloop#1{%%
  \foreach \x in {#1} {\current@item \x}}

%% version a la `ae`
\def\@ae@myloop#1,#2\@nil{%%
  \current@item{#1}%%
  \expandafter\ifx\expandafter\relax\detokenize{#2}\relax\else
    \@ae@myloop#2\@nil
   \fi
}
\def\ae@myloop#1{%%
  \@ae@myloop#1,\@nil
}

\def\listoffruit#1#2#3{%%
  \def\my@item@count{0}%%
  \noindent
  List of type \texttt{#1}: \parbox[t]{3in}{\raggedright#3}
  \begin{itemize}[topsep=4pt,itemsep=2pt]
    \csname#1@myloop\endcsname{#2}%%
  \end{itemize}
  Total number of bulleted items: \my@item@count
  \par \vspace{2ex}\hrule\par \vspace{2ex}
  }

\ExplSyntaxOn
\NewDocumentCommand{\expl@myloop}{ m }
{
  \clist_map_inline:nn{#1}{\current@item {##1}}
}
\ExplSyntaxOff

\makeatother
\def\apples{apples}
\def\bananas{bananas}
\def\cherries{cherries}

\begin{document}

\listoffruit{etoolbox}{apples,, oranges, bananas ,cherries}{Ignores leading spaces and empty items. Trailing spaces not ignored.}

\listoffruit{@for}{apples,, oranges, bananas ,cherries}{Empty lines and trailing or leading spaces not ignored.  Something goes on with last item in list.}

\listoffruit{@tfor}{\apples,{} {oranges}\bananas\cherries}{Spaces ignored, all other token respected, bracketed tokens treated as one.}

\listoffruit{pgffor}{apples,, oranges, bananas ,cherries}{Ignores leading spaces, empty items and trailing spaces not ignored.}

\listoffruit{ae}{apples,, oranges, bananas ,cherries}{Leading or trailing spaces not ignored.  Empty items not ignored.}

\listoffruit{expl}{apples,, oranges, bananas ,cherries}{Trailing or leading spaces ignored.   Empty items ignored.}

\end{document}

Bildbeschreibung hier eingeben

Mir bekannte Probleme:

  • Ich glaube, \@fores ist nicht erweiterbar,
  • \cslist_map_inline:nnist erweiterbar, jedoch mit Einschränkungen: d. h., es ist in einem Argument vom Typ - nicht erweiterbar f.
  • pgfforDie \foreachSchleife wird innerhalb einer Gruppe ausgeführt. Sie müssen also Informationen aus der Gruppe für die spätere Verwendung speichern \gdefoder verwenden. Ich habe noch nicht vollständig untersucht, welche anderen der hier vorgestellten Schleifen eine ähnliche\xdegMangel(nicht sicher, ob das die richtige Wortwahl ist). Ich habe keine Ahnung, ob \foreaches erweiterbar ist oder nicht.
  • Einige Methoden handhaben ihre Listen recht gut, egal ob sie explizit oder implizit über ein Makro übergeben werden. Beispielsweise weiß pgffor's \foreach, was mit einer über ein Makro übergebenen Liste zu tun ist. etoolbox's \forcsvlisterfordert, dass dieses Makro zuerst erweitert wird: daher ist meine erste Abbildung von a \forcslistso kompliziert, wie sie ist.

Was mich hier interessiert ist:

  1. Antworten, die auf die Stärken und Schwächen der verschiedenen hier vorgestellten Ansätze eingehen, wie am Anfang dieses Beitrags aufgelistet, aber nicht unbedingt auf diese Vorschläge beschränkt, da mir andere wichtige Punkte möglicherweise nicht bewusst sind. Ich bin mir beispielsweise nicht wirklich sicher, welche erweiterbar sind.
  2. Antworten, die andere Methoden zum Durchlaufen einer Liste von Elementen sowie deren bekannte Schwächen und Stärken vorstellen.
  3. Antworten, die realistische Beispiele veranschaulichen können, für die man eine solche Schleife in einem erweiterbaren Kontext verwenden möchte
  4. Antworten, die veranschaulichen, wie man innerhalb der Gruppe gesammelte Informationen für die spätere Verwendung speichern kann.

Antwort1

Ich schlage eine andere Definition vor von\current@item

\def\current@item#1{%
  \stepcounter{item@count}
  \item $|$#1$|$\ $|$\texttt{\detokenize{#1}}$|$%
}

Die Ausgabe zeigt also auch, was wirklich als Argument übergeben wird. Außerdem habe ich die komplizierte Verwaltung von \my@item@countdurch einen einfachen Zähler ersetzt. Ich kommentiere nichts zu \@tfor, da es sich um ein anderes Tool handelt, das nicht für durch Kommas getrennte Listen entwickelt wurde.

  1. etoolbox: \forcsvlistentfernt keine nachstehenden Leerzeichen; Ihre Definition ist zu kompliziert, weil

    %% `etoolbox`
    \def\etoolbox@myloop#1{%%
      \forcsvlist\current@item{#1}}
    

    reicht aus. Elemente werden explizit übergeben.

  2. \@forist das grundlegende Werkzeug, das im LaTeX-Kernel definiert ist. Führende und nachfolgende Leerzeichen werden nicht entfernt. Elemente werden als übergeben \x, die Steuersequenz, die nach verwendet wird \@for.

  3. \foreachentfernt keine nachstehenden Leerzeichen. Elemente werden als übergeben \x, die Steuersequenz, die nach verwendet wird \foreach.

  4. aeist grundsätzlich wie \@for, funktioniert aber durch Erweiterung. Führende und nachfolgende Leerzeichen werden nicht entfernt. Elemente werden explizit übergeben.

  5. explentfernt führende und nachfolgende Leerzeichen, aber auch leere Elemente; Elemente werden explizit übergeben.

\documentclass{article}
\usepackage[margin=0.5in,paperheight=15in]{geometry}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{pgffor}
\usepackage{enumitem}
\makeatletter

\newcounter{item@count}
%% \rules to emphasize how spaces are seen and treated!
\def\current@item#1{%
  \stepcounter{item@count}
  \item $|$#1$|$\ $|$\texttt{\detokenize{#1}}$|$%
}

%% `etoolbox`
\def\etoolbox@myloop#1{%%
  \forcsvlist\current@item{#1}}

%% \@for
\def\@for@myloop#1{%%
  \@for \x:=#1\do{\current@item \x}}

%% pgffor
\def\pgffor@myloop#1{%%
  \foreach \x in {#1} {\typeout{pgf:\x}\current@item \x}}

%% version a la `ae`
\def\@ae@myloop#1,#2\@nil{%%
  \current@item{#1}%%
  \if\relax\detokenize{#2}\relax\else
    \@ae@myloop#2\@nil
   \fi
}
\def\ae@myloop#1{%%
  \@ae@myloop#1,\@nil
}

\def\listoffruit#1#2{%%
  \setcounter{item@count}{0}%%
  \noindent
  List of type \texttt{#1}
  \begin{itemize}[topsep=4pt,itemsep=2pt]
    \csname#1@myloop\endcsname{#2}%%
  \end{itemize}
  Total number of bulleted items: \arabic{item@count}%
  \par \vspace{2ex}\hrule\par \vspace{2ex}
  }

\ExplSyntaxOn
\NewDocumentCommand{\expl@myloop}{ m }
{
  \clist_map_inline:nn{#1}{\current@item {##1}}
}
\ExplSyntaxOff

\makeatother

\begin{document}

\listoffruit{etoolbox}{apples,, oranges, bananas ,cherries}

\listoffruit{@for}{apples,, oranges, bananas ,cherries}

\listoffruit{pgffor}{apples,, oranges, bananas ,cherries}

\listoffruit{ae}{apples,, oranges, bananas ,cherries}

\listoffruit{expl}{apples,, oranges, bananas ,cherries}

\end{document}

Bildbeschreibung hier eingeben

Ich würde eine weitere Schleife hinzufügen expl3, die auch leere Elemente berücksichtigt:

\ExplSyntaxOn
\NewDocumentCommand{\seq@myloop}{ m }
 {
  \seq_set_split:Nnn \l_tmpa_seq { , } { #1 }
  \seq_map_inline:Nn \l_tmpa_seq { \current@item {##1} }
 }
\ExplSyntaxOff

(von der Verwendung wird natürlich \l_tmpa_seqabgeraten. Es ist besser, eine neue Variable zuzuweisen.)

Bildbeschreibung hier eingeben

Der Vergleich sollte keinen Zweifel lassen. Der einzige Punkt, in dem \foreaches überlegen ist, ist die Behandlung von „unvollständigen Listen“, wie z. B. 1,2,...,20.

Antwort2

LuaLaTeX:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{filecontents}
\begin{document}
    \newcommand{\drawCircle}[1]{\tikz \draw (0,0) circle (#1);}
    \begin{filecontents*}{testlua.lua}
        for i=1,10 do
            tex.print("\\drawCircle{",0.1*i,"}")
        end
    \end{filecontents*}
    \directlua{dofile('testlua.lua')}
\end{document}

verwandte Informationen