迭代列表的一部分

迭代列表的一部分

我知道这个包裹电子工具箱有一个 \foreach 命令。

我想设置一次列表并多次使用它。在示例中,我将设置 \mylist 等于逗号分隔值列表 10,20,30,40,50。

我想要一个像这样的命令

\forparteach 3 \var \in {10,20,30, 40,50} {
  \var
}

是相同的

\foreach \var \in {10,20,30} {
   \var
}

甚至

\forparteach {1,3,4,2,5,5} \var \in {10,20,30,40,50} {
   \var
}

是相同的

\foreach \var \in {10,30,40,20,50,50} {
   \var
}

是否有任何软件包可以做到这一点或者有一个简单的解决方案?

谢谢!

答案1

这两件事都可以用当前的宏\foreach直接实现。更具体地说,\breakforeach它允许您中断循环,从而允许您将循环限制在第一个n条目。并且您可以将列表存储在数组中并访问其元素。请注意,我甚至没有尝试编写新的宏,\forparteach因为\foreach它非常微妙,我不敢乱搞它。

\documentclass{article}
\usepackage{pgffor}
\begin{document}
\section*{Cutting a loop off at some number}
\foreach \var [count=\n] in {10,20,30,40,50} 
{ \var 
\ifnum\n>2 
\breakforeach 
\fi
}
\section*{Selecting a subset of items from a list/an array}
\def\myarray{{10,20,30,40,50}}
\foreach \var [evaluate=\var as \myindex using {int(\var-1)}] in {1,3,4,2,5,5} {
\pgfmathparse{\myarray[\myindex]}\pgfmathresult
}
\end{document}

在此处输入图片描述

答案2

您可以实现自己的 foreach 循环。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\xforeach}{sO{}mm}
 {
  \IfBooleanTF { #1 }
   {
    \marks_xforeach:Vnn #3 { #2 } { #4 }
   }
   {
    \marks_xforeach:nnn { #3 } { #2 } { #4 }
   }
 }

\keys_define:nn { marks/xforeach }
 {
  upto  .int_set:N   = \l_marks_xforeach_upto_int,
  items .clist_set:N = \l_marks_xforeach_items_clist,
 }

\clist_new:N \l__marks_xforeach_main_clist
\seq_new:N \l__marks_xforeach_items_seq
\seq_new:N \l__marks_xforeach_main_seq

\cs_new_protected:Nn \marks_xforeach:nnn
 {
  \clist_set:Nn \l__marks_xforeach_main_clist { #1 }
  \keys_set:nn { marks/xforeach } { upto=-1, items=, #2 }
  \cs_set_protected:Nn \__marks_xforeach_cycle:n { #3 }

  \seq_clear:N \l__marks_xforeach_items_seq
  \clist_if_empty:NTF \l_marks_xforeach_items_clist
   {% items not specified
    \int_compare:nT { \l_marks_xforeach_upto_int = -1 }
     {
      \int_set:Nn \l_marks_xforeach_upto_int
       { \clist_count:N \l__marks_xforeach_main_clist }
     }
    \int_step_inline:nn { \l_marks_xforeach_upto_int }
     {
      \seq_put_right:Nn \l__marks_xforeach_items_seq { ##1 }
     }
   }
   {% items
    \seq_set_from_clist:NN \l__marks_xforeach_items_seq \l_marks_xforeach_items_clist
   }
  \seq_clear:N \l__marks_xforeach_main_seq
  \seq_map_inline:Nn \l__marks_xforeach_items_seq
   {
    \seq_put_right:Nx \l__marks_xforeach_main_seq
     {
      \clist_item:Nn \l__marks_xforeach_main_clist { ##1 }
     }
   }
  \seq_map_function:NN \l__marks_xforeach_main_seq \__marks_xforeach_cycle:n
 }
\cs_generate_variant:Nn \marks_xforeach:nnn { V }

\ExplSyntaxOff

\begin{document}

\newcommand{\myarray}{10,20,30,40,50}

\xforeach{10,20,30,40,50}{(Item: #1) }

\xforeach*{\myarray}{(Item: #1) }

\xforeach[upto=3]{10,20,30,40,50}{(Item: #1) }

\xforeach*[upto=3]{\myarray}{(Item: #1) }

\xforeach[items={1,3,4,2,5,5}]{10,20,30,40,50}{(Item: #1) }

\xforeach*[items={1,3,4,2,5,5}]{\myarray}{(Item: #1) }

\end{document}

在此处输入图片描述

需要注意的几点:与 不同\foreach,循环不是按组执行的;当前项用 表示,#1而不是通过指定保存它的宏来表示。 *-variant 接受宏作为第二个参数,而不是显式列表。

人们可以依赖类似括号的存在\foreach,但在我看来,使用选项和特定命令更清晰。

答案3

您可以使用 来做这些事情xinttools\xintFor/\xintFor*循环不会创建组。另一方面,它们目前没有实现一些很好的\foreach语法,例如1, 2, ..., 5。并且没有简单的方法来创建key=value选择,因为xinttools它不是像 LaTeX3 提供的成熟编程接口,而是一小段有用的宏(也可以在 Plain TeX 下使用)。

\documentclass{article}

\usepackage{xinttools}
\usepackage{parskip}
\begin{document}\pagestyle{empty}\thispagestyle{empty}

\section*{Cutting a loop off at some number}

First three:

\begin{itemize}
% this uses \xintFor* as argument will be {item1}{item2}....
% i.e. a "list" in the sense of xinttools doc, not a
% "comma separated list"
 \xintFor* #1 in {\xintKeep{3}{\xintCSVtoList{10,20,30,40,50}}}
 \do 
  {\item (Item: #1)}
\end{itemize}

Last two:

\begin{itemize}
 \xintFor* #1 in {\xintKeep{-2}{\xintCSVtoList{10,20,30,40,50}}}
 \do 
  {\item (Item: #1)}
\end{itemize}

Trim first two:

\begin{itemize}
 \xintFor* #1 in {\xintTrim{2}{\xintCSVtoList{10,20,30,40,50}}}
 \do 
  {\item (Item: #1)}
\end{itemize}

Trim last two:

\begin{itemize}
 \xintFor* #1 in {\xintTrim{-2}{\xintCSVtoList{10,20,30,40,50}}}
 \do 
  {\item (Item: #1)}
\end{itemize}

Nested keep/trim (keep 2 after having trimmed 2):

\begin{itemize}
 \xintFor* #1 in {\xintKeep{2}{\xintTrim{2}{\xintCSVtoList{10,20,30,40,50}}}}
 \do 
  {\item (Item: #1)}
\end{itemize}


\clearpage
\section*{Selecting a subset of items from a list}

Selecting items 1, 3, 4, 2, 5, 5:

% for better efficiency, let's convert comma separated values
% in a "list" (in xinttools terminology) first, once and for all
% because \xintNthElt macro expects such as list

\oodef\MyListOfBracedItems{\xintCSVtoList{10,20,30,40,50}}

\begin{itemize}
% this uses the non-starred \xintFor, which accepts comma separated values
 \xintFor #1 in {1, 3, 4, 2, 5, 5}
 \do 
  {\item (Item: \xintNthElt{#1}{\MyListOfBracedItems})}
\end{itemize}

It is also possible to create an ``array'', for better efficiency afterwards:

\xintAssignArray\xintCSVtoList{10, 20, 30, 40, 50}\to\MyArray

\begin{itemize}
% this uses the starred \xintFor, which accepts braced items (or
% single tokens; spaces skipped)
 \xintFor* #1 in {1 3 4 2 5 5}
 \do 
  {\item (Item: \MyArray{#1})}
\end{itemize}


\end{document}

第 1 页

在此处输入图片描述

第2页

在此处输入图片描述

相关内容