为什么 \foreach \x in {0,1,...,0}{} 执行两次迭代(而不是一次)?

为什么 \foreach \x in {0,1,...,0}{} 执行两次迭代(而不是一次)?

请参阅以下 MWE 以更好地理解我的意思。

\documentclass[preview,border=12pt]{standalone}
\usepackage{pgffor,multido}
\begin{document}
\section*{foreach}
\foreach \ix in {0,1,...,3}{%
    \foreach \iy in {0,1,...,\ix}{(\ix,\iy)\ }\endgraf}

\section*{multido}
\multido{\ix=0+1}{4}{%
    \multido{\iy=0+1}{\the\numexpr\ix+1\relax}{(\ix,\iy)\ }\endgraf}
\end{document}

在此处输入图片描述

为何无法\foreach \x in {0,1,...,0}{}进行第二次迭代?

答案1

\foreach命令有其怪癖;但是,您的 MWE 中显示的行为与第 56 节一致PGF 手册 (2.10),详细描述了...内部所起的作用\foreach

考虑\foreach \xx in {x,y,...,z}。差值 d= y-x用于“填充”由...(参见第 505 页) 隐式指定的元素:

在这种情况下,列表阅读的部分x,y,...,z被替换为x, x + d, x + 2d, x + 3d,... x + md,其中最后的点是语义点,而不是句法点。值 m 是最大数字,使得如果 d 为正,则x+ md ≤ ,或者如果 d 为负,则+ md ≥ 。zxz

可能违反直觉的是,前两次迭代(使用xy)将执行无论 的值z是什么

解决问题的一种方法是删除元素y,如 PGF 手册(同上)所述:

如果...在列表中的第一个项目之后立即使用,即如果存在x但没有y,则差异d显然无法计算,并且1如果点后面的数字z大于,则设置为,如果小于,则x设置为。−1z

\foreach \iy in {0,...,0},当\ix具有值时出现,仅根据需要对0进行迭代。0

\documentclass[preview,border=12pt]{standalone}
\usepackage{pgffor,multido}
\begin{document}
\section*{foreach}
\foreach \ix in {0,1,...,3}{%
    \foreach \iy in {0,...,\ix}{(\ix,\iy)\ }\endgraf} % omit 1 here

\section*{multido}
\multido{\ix=0+1}{4}{%
    \multido{\iy=0+1}{\the\numexpr\ix+1\relax}{(\ix,\iy)\ }\endgraf}
\end{document}

在此处输入图片描述


编辑: 据观察@Sigur,上述修复仅在增量等于 1 时才有效,就像 OP 示例中的情况一样。\foreach在增量不为 1 的情况下,需要进行更实质性的修改才能相应地改变 的行为。比如说,如果你想让它的\foreach \xx {x,y,...,z}行为更像 Matlabfor循环,

for i=x:y-x:z
  % for-loop body
end

您必须考虑 9 种不同的情况,具体取决于 、 和 相互之间的比较方式xy< z、= 或 >):

  1. x< y< z:列表无变化;
  2. x< y= z:列表应该是x,y
  3. x< y> z:列表应该为空;
  4. x= y< z:这会引发TeX capacity exceeded错误;
  5. x= y< z:这会引发TeX capacity exceeded错误;
  6. x= y< z:这会引发TeX capacity exceeded错误;
  7. x> y< z:列表应该为空;
  8. x> y= z:列表应该是x,y
  9. x>> yz列表无变化;

您可以在进入循环之前比较xy和,然后根据您所处的 9 种情况中的哪一种,以编程方式生成要在中使用的相应列表。但是,我觉得这种方法超出了 OP 问题的范围,可能值得在其他地方得到适当的答案......z\foreach\foreach

相关内容