6

In following test:

\documentclass[spanish,10pt]{beamer}
\usepackage{pgfplots}

\begin{document}

\foreach \x in {2,4,...,12} {
   \x
}

\foreach \x in {2,4,...,4} {
   \x
}

\foreach \x in {2,4,...,2} {
   \x
}

\foreach \x in {2,4,...,-1} {
   \x
}

\end{document}

result is the following four lines:

2 4 6 8 10 12
2 4
2 4
2 4

first two lines are as expected but final two lines are not: I expected "2" and empty line (as usual in other programming languages).

Any hint to obtain these results? (in real source, the final number is an unknown argument).

4
  • it's a bit under documented but if you use the a,b,...,z form then I think you always get a,b and then a possibly empty iteration until the counter, stepping by b-a is at least z. – David Carlisle Nov 6 '16 at 16:56
  • 1
    I think \foreach processes each item in the list; it decides if it is numeric and, in this case it saves the difference with the previous item, if numeric, instead of the default 1; then it goes to the next; if it is ..., it goes on using the remembered difference until going beyond the next value (which should be numeric). It definitely does not parse the entire list before starting. – egreg Nov 6 '16 at 17:12
  • The pgf \foreach loop structure is meant for cases where there is something to 'do' based on a pattern: I suspect that the behaviour if you give defective input such as 2,4,...,-1 is undefined. – Joseph Wright Nov 6 '16 at 17:58
  • See tex.stackexchange.com/questions/327699/… for a macro that does what you explain in the addition. – egreg Nov 6 '16 at 20:14
5

Apparently, \foreach \x in {<a>,<b>,...,<c>}{<code>} always executes the cycle with <a> and <b>; then it sees ... and decides what the difference between <a> and <b> is. Only at this point it starts a recursion which terminates when the next number exceeds <c> (in absolute value).

If your values are only integers, you can use expl3 that also has other benefits; for instance, you use #1 instead of \x and you need no trick for expansion; moreover, no group is opened.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
% key-value form
\NewDocumentCommand{\xforeach}{mm}
 {
  \keys_set:nn { pasaba/xforeach }
   {
    start = 0,step = 1,end = 0,#1
   }
  \int_step_inline:nnnn
   { \l_pasaba_xforeach_start_int }
   { \l_pasaba_xforeach_step_int }
   { \l_pasaba_xforeach_end_int }
   { #2 }
 }
\keys_define:nn { pasaba/xforeach }
 {
  start .int_set:N = \l_pasaba_xforeach_start_int,
  step  .int_set:N = \l_pasaba_xforeach_step_int,
  end   .int_set:N = \l_pasaba_xforeach_end_int,
 }
% macro form
\NewDocumentCommand{\sforeach}{mmmm}
 {
  \int_step_inline:nnnn { #1 } { #2 } { #3 } { #4 }
 }
\ExplSyntaxOff

\begin{document}

\textbf{Key-value form}

$(2,2,12)$: \xforeach{start = 2,step = 2,end = 12}{#1 }

$(2,2,4)$: \xforeach{start = 2,step = 2,end = 4}{#1 }

$(2,2,2)$: \xforeach{start = 2,step = 2,end = 2}{#1 }

$(2,2,-1)$: \xforeach{start = 2,step = 2,end = -1}{#1 }

\bigskip

\textbf{Command form}

$(2,2,12)$: \sforeach{2}{2}{12}{#1 }

$(2,2,4)$: \sforeach{2}{2}{4}{#1 }

$(2,2,2)$: \sforeach{2}{2}{2}{#1 }

$(2,2,-1)$: \sforeach{2}{2}{-1}{#1 }

\end{document}

enter image description here

Now, suppose you have some \foreach in a macro, say

\newcommand{\foo}[1]{%
  \foreach \x in {2,4,...,#1}{do something with \x}%
}

You can turn it into a macro based on \sforeach with

\newcommand{\foo}[1]{%
  \sforeach{2}{2}{#1}{do something with ##1}%
}

The parameter #1 in \sforeach must become ##1, because it is used inside a macro definition.

8
  • Of course this solution won't deal with all the other kinds of sequences that the TikZ version can: \foreach \x in {A,B,...,Z} {\x} which yields a letter sequence, or \foreach \x in {2^1, 2^,...,2^10}{$\x$} which typesets powers of two, etc. See page 902 of the docs if you want to extend your solution. ;-) – Alan Munn Nov 6 '16 at 22:26
  • @AlanMunn See my answer to the question I linked in a comment above: tex.stackexchange.com/questions/327699/… – egreg Nov 6 '16 at 22:41
  • @egreg: very nice solution. Are you so kind of add some more comments in the code? In particular, I do not see the real "body" of the new commands, that is, where they loop o calls a loop method to print all range elements. – pasaba por aqui Nov 7 '16 at 11:54
  • @pasabaporaqui The loop is \int_step_inline:nnnn {<start>}{<step>}{<end>}{<code>}, that's the power of expl3! – egreg Nov 7 '16 at 11:56
  • An improvement of this solution could be that \sforeach accepts any block of commands and can be used inside a \newcommand. I've edited original question to show some examples. – pasaba por aqui Nov 7 '16 at 12:35
6

From the TikZ documentation (p.902)

Normally, when a list item ... is encountered, there should already have been two list items before it, which where numbers. Examples of numbers are 1, -10, or -0.24. Let us call these numbers x and y and let d := y − x be their difference. Next, there should also be one number following the three dots, let us call this number z.

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.

I think implicitly m is intended to be a positive integer, and for negative values of z formula is incorrectly described, (as noted in the comments) so in your last three cases, d=2 and m=1 for all cases, which leads to the sequence 2, 2+d= 2,4.

If you want to have a list that just contains (2) you can use:

\foreach \x in {2,...,2} {
   \x
}

I don't think there's a way to end up with a blank list, given the way the list syntax works.

As percusse notes in the comments, the first one or two elements of the list are always executed. To see this, here's a version of your code with a command added to display the value of the increment and the current value at each iteration. (These are lengths defined in pgffor.code.tex).

\documentclass{article}
\usepackage{pgffor}
\usepackage{xcolor}
\makeatletter
\newcommand\dbug{\textcolor{red}{\strip@pt\pgffor@iter;\strip@pt\pgffor@skip}\ }
\makeatother

\begin{document}

\foreach \x in {2,4,...,12} {
   \dbug\x
}

\foreach \x in {2,4,...,4} {
   \dbug\x
}

\foreach \x in {2,4,...,2} {
   \dbug\x
}

\foreach \x in {2,4,...,-1} {
   \dbug\x
}

\end{document}

formatted output of code

8
  • I don't think the description is really accurate and that no list is actually built up; otherwise, the case 2,4,...,-1 would only process 2. In this case m should be –2. – egreg Nov 6 '16 at 17:15
  • Please, where I can find the documentation? – pasaba por aqui Nov 6 '16 at 17:23
  • @pasabaporaqui The documentation is in the TikZ documentation. You can use texdoc tikz from the terminal to find it. – Alan Munn Nov 6 '16 at 17:25
  • @egreg The description in the documentation or my interpretation of it? I think m is required to be a positive integer. – Alan Munn Nov 6 '16 at 17:26
  • Probably documentation must change from "The value m is the largest ..." to "The value m is the maximum of 1 and the largest ..." – pasaba por aqui Nov 6 '16 at 17:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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