for ループを生成するためのさまざまな方法の違いは何ですか?

for ループを生成するためのさまざまな方法の違いは何ですか?

私は、カンマ区切りのリストなどをループ処理するために利用できるさまざまな方法について考えていました。特に、それらのさまざまな長所と短所について考えていました。言い換えると、次のようなことについて考えていました (ただし、このリストに限定されるわけではありません)。

  1. 拡張可能かどうか
  2. 空のアイテムをどのように処理するか、
  3. 余分な先頭と末尾のスペースをどのように処理するか
  4. ループ内の情報を後で使用するために保存するために\def/ を使用できるかどうか、または/\edefを使用する必要があるかどうか。\gdef\xdef

順不同ですが、私がよく知っているループ メソッドのリストを以下に示します。次のリストは、\current@item反復処理で現在の項目をフォーマットするための、1 つの引数を取るマクロを表しています。

からのコマンドの使用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}}

etoolboxパッケージの使用

%% `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}}

pgfforパッケージの使用

%% 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
}

さらに、次のようなさまざまな方法もありますexpl3(非常に多くの方法があるため、すべてを網羅することはできません)。

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

以下に、それぞれの結果を示す MWE を示します (LaTeX3 バージョンも 1 つ含む)。

\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}

ここに画像の説明を入力してください

私が認識している問題:

  • \@for拡張できないと思いますが、
  • \cslist_map_inline:nn拡張可能ですが、制限があります。つまり、 -type 引数では拡張できませんf
  • pgffor\foreachループはグループ内で実行されます。そのため、グループ内の情報を後で使用するために保存するに\gdefは、またはを使用する必要があります\xdeg。ここで紹介した他のループのどれが同様の機能を持つかは、まだ十分に調査していません。欠点(それが正しい言葉の選択かどうかはわかりません)。拡張可能かどうかはわかりません\foreach
  • いくつかのメソッドは、明示的に渡されるか、マクロを介して暗黙的に渡されるかに関係なく、リストをかなりうまく処理します。たとえば、pgfforは、\foreachマクロを介して渡されたリストをどのように処理するかを認識しています。 では、まずそのマクロを展開する必要がありetoolboxます\forcsvlist。これが、 の最初の図が\forcslist非常に複雑な理由です。

私がここで興味を持っているのは次の点です。

  1. この投稿の冒頭で箇条書きしたように、ここで提示されたさまざまなアプローチの長所と短所に対処する回答ですが、他の重要な問題を認識していない可能性があるため、必ずしもそれらの提案に限定されるわけではありません。たとえば、どれが拡張可能かはよくわかりません。
  2. 既知の弱点と強みとともに、アイテムのリストを反復処理するための他の方法を紹介する応答。
  3. 拡張可能なコンテキストでそのようなループを使用したい現実的な例を説明できる応答
  4. グループ内から収集した情報を後で使用するために保存する方法を示す応答。

答え1

私は別の定義を提案します\current@item

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

そのため、出力には実際に引数として渡されたものも表示されます。また、 の複雑な管理を\my@item@count単純なカウンターに変更しました。 についてはコメントしません。\@tforは、カンマ区切りリスト用に設計されていない別のツールです。

  1. etoolbox:\forcsvlistは末尾のスペースを削除しません。定義が複雑すぎるため、

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

    十分です。項目は明示的に渡されます。

  2. \@forは、LaTeX カーネルで定義されている基本ツールです。先頭と末尾のスペースは削除されません。項目は\x、 の後に使用される制御シーケンスとして渡されます\@for

  3. \foreach末尾のスペースは削除されません。項目は\xの後に使用される制御シーケンスとして渡されます\foreach

  4. aeは基本的に と似ています\@forが、拡張によって動作します。先頭と末尾のスペースは削除されません。項目は明示的に渡されます。

  5. expl先頭と末尾のスペースを削除しますが、空の項目も削除します。項目は明示的に渡されます。

\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}

ここに画像の説明を入力してください

expl3空の項目も考慮する別のループを追加します。

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

(もちろん、 を使用すること\l_tmpa_seqは推奨されません。新しい変数を割り当てる方がよいでしょう)。

ここに画像の説明を入力してください

比較してみると、疑問の余地はありません。 が優れている唯一の点\foreachは、 などの「不完全なリスト」の処理です1,2,...,20

答え2

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}

関連情報