Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

See the following MWE to understand what I mean better.

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

enter image description here

Why cannot \foreach \x in {0,1,...,0}{} discharge the second iteration?

share|improve this question

1 Answer 1

up vote 13 down vote accepted

The \foreach command has its quirks; however, the behaviour shown in your MWE is consistent with section 56 of the PGF manual (2.10), which describes in detail what the ... does inside \foreach.

Consider \foreach \xx in {x,y,...,z}. The difference d=y-x is used to "fill in" the elements implicitly specified by ... (see p.505):

In this situation, the part of the list reading x,y,...,z is replaced by x, x + d, x + 2d, x + 3d, ... x + md, where the last dots are semantic dots, not syntactic dots. The value m is the largest number such that x + md ≤ z if d is positive or such that x + md ≥ z if d is negative.

What is perhaps counterintuitive is that the first two iterations (using x and y) will be performed no matter what the value of z is.

One way of fixing your problem is to drop the y element, as described by the PGF manual (ibid.):

If the ... is used right after the first item in the list, that is, if there is an x, but no y, the difference d obviously cannot be computed and is set to 1 if the number z following the dots is larger than x and is set to −1 if z is smaller.

\foreach \iy in {0,...,0}, which arises when \ix has value 0, only iterates over 0, as desired.

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

enter image description here


Edit: As observed by @Sigur, the fix above is only effective if the increment is equal to 1, as is the case in the OP's example. A more substantial hack would be required to alter the behaviour of \foreach accordingly in cases where the increment is different from 1. If, say, you wanted to make \foreach \xx {x,y,...,z} behave more like a Matlab for loop,

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

you would have to consider 9 different cases, depending on how x, y, and z compare to one another (<, =, or >):

  1. x<y<z: no changes to the list;
  2. x<y=z: the list should be x,y;
  3. x<y>z: the list should be empty;
  4. x=y<z: this throws a TeX capacity exceeded error;
  5. x=y<z: this throws a TeX capacity exceeded error;
  6. x=y<z: this throws a TeX capacity exceeded error;
  7. x>y<z: the list should be empty;
  8. x>y=z: the list should be x,y;
  9. x>y>z: no changes to the list;

You could compare x, y, and z before entering the \foreach loop and programmatically generate the corresponding list to be used in \foreach, depending on which of the 9 cases you're in. However, I feel that this approach goes beyond the scope of the OP's question and may deserve a proper answer somewhere else...

share|improve this answer
    
@Jubobs, this only works because the step is 1? If we want the same result but only for even numbers, what to do? –  Sigur Oct 26 '13 at 16:58
    
@Sigur Yes, the fix above only works because the increment used by the OP in the inner foreach loop happens to be equal to 1. You need to elaborate upon what you mean by "the same result". Of course, you could modify the behaviour of \foreach in {x,y,...,z} to your liking, depending on how x, y, and z compare to one another (<, =, or >). Among the 6 possible cases (the 3 cases in which x=y will cause TeX to return an error), I'm guessing you would like the list effectively used by \foreach to be: 1) empty if x>y<z or x<y>z and 2) x,y if y=z. Am I correct? –  Jubobs Oct 26 '13 at 17:59
    
I'd like to do the same triangle but using step equal to 2 or maybe 3, for example. –  Sigur Oct 26 '13 at 18:01

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.