# Problem when applying foreach loop

I'm trying to find the minimum x coordinate in a set of TikZ coordinates.

Consider this code

\documentclass[tikz]{standalone}
\usetikzlibrary{positioning}
\newdimen\x
\newdimen\xmin
\xmin=10000pt
\newdimen\y
\begin{document}
\begin{tikzpicture}[every node/.style={draw}]
\node (1) {182};
\node[below=of 1] (2) {183731468};
\node[below=of 2] (3) {74632};
\path (1.west); \pgfgetlastxy{\x}{\y}
\ifdim\x<\xmin \xmin=\x \fi
\fill[red] (\xmin,\y) circle (1pt);
\path (2.west); \pgfgetlastxy{\x}{\y}
\ifdim\x<\xmin \xmin=\x \fi
\fill[red] (\xmin,\y) circle (1pt);
\path (3.west); \pgfgetlastxy{\x}{\y}
\ifdim\x<\xmin \xmin=\x \fi
\fill[red] (\xmin,\y) circle (1pt);
\end{tikzpicture}
\end{document}


and this code

\documentclass[tikz]{standalone}
\usetikzlibrary{positioning}
\newdimen\x
\newdimen\xmin
\xmin=10000pt
\newdimen\y
\begin{document}
\begin{tikzpicture}[every node/.style={draw}]
\node (1) {182};
\node[below=of 1] (2) {183731468};
\node[below=of 2] (3) {74632};
\foreach \i in {1,2,3} {
\path (\i.west); \pgfgetlastxy{\x}{\y}
\ifdim\x<\xmin \xmin=\x \fi
\fill[red] (\xmin,\y) circle (1pt);
}
\end{tikzpicture}
\end{document}


These are the outputs of the first code (left) and the second code (right) side by side:

Look at the dot at the bottom. The first code gives the intended output, but the second doesn't.

Why? And how to modify the \foreach loop in the second code so that it gives the same output as the first?

In the \foreach variant, you are in a group when setting the dimension, so the "outside" value won't change. So you need to make the dimension global (or smuggle it out of the group). Here I made it global by just adding \global before \xmin=\x.

\documentclass[tikz]{standalone}
\usetikzlibrary{positioning}
\newdimen\x
\newdimen\xmin
\xmin=10000pt
\newdimen\y
\begin{document}
\begin{tikzpicture}[every node/.style={draw}]
\node (1) {182};
\node[below=of 1] (2) {183731468};
\node[below=of 2] (3) {74632};
\foreach \i in {1,2,3} {
\path (\i.west); \pgfgetlastxy{\x}{\y}
\ifdim\x<\xmin \global\xmin=\x \fi
\fill[red] (\xmin,\y) circle (1pt);
}
\end{tikzpicture}
\end{document}


ADDENDUM: Of course, there are loops which do not introduce groups. The arguably simplest of those is the built-in \loop.

\documentclass[tikz]{standalone}
\usetikzlibrary{positioning}
\newdimen\x
\newdimen\xmin
\xmin=10000pt
\newdimen\y
\newcounter{loopi}
\begin{document}
\begin{tikzpicture}[every node/.style={draw}]
\node (1) {182};
\node[below=of 1] (2) {183731468};
\node[below=of 2] (3) {74632};
\setcounter{loopi}{0}
\loop
\stepcounter{loopi}
\path (\number\value{loopi}.west); \pgfgetlastxy{\x}{\y}
\ifdim\x<\xmin \xmin=\x \fi
\fill[red] (\xmin,\y) circle (1pt);
\ifnum\number\value{loopi}<3\repeat
\end{tikzpicture}
\end{document}

• @JouleV You only change the local but not the outside value. (This is also the reason why \draw[blue] ... renders only the ... but not every other path blue. Likewise, if you say \tikz[blue]{....} everything in the tikzpicture will be blue, but not outside, and so on.) In TeX all macros are local unless you explicitly make them global.
– user121799
Apr 14 '19 at 14:56

You can use a different loop that doesn't do grouping. Instead of \i you use simply #1.

\documentclass[border=4]{standalone}
\usepackage{xparse}
\usepackage{tikz}

\usetikzlibrary{positioning}

\ExplSyntaxOn
\NewDocumentCommand{\nforeach}{mmm}
{
\cs_set:Nn \joulev_nforeach:n { #3 }
\int_step_function:nnN { #1 } { #2 } \joulev_nforeach:n
}
\ExplSyntaxOff

\newdimen\x
\newdimen\xmin
\newdimen\y

\begin{document}
\begin{tikzpicture}[every node/.style={draw}]
\xmin=10000pt
\node (1) {182};
\node[below=of 1] (2) {183731468};
\node[below=of 2] (3) {74632};
\nforeach{1}{3}{
\path (#1.west); \pgfgetlastxy{\x}{\y}
\ifdim\x<\xmin \xmin=\x \fi
\fill[red] (\xmin,\y) circle (1pt);
}
\end{tikzpicture}
\end{document}


• Maybe I will have to start learning expl3 syntax soon. What does those commands inside \ExplSyntax mean?
– user156344
Apr 14 '19 at 15:27
• @JouleV The first line sets a temporary function according to the code in the third argument; the second line does a loop from the starting point (first argument) to the final point (second argument). No fancy syntax like \foreach, but for most cases it's sufficient. You find a more elaborate implementation at tex.stackexchange.com/a/329628/4427 Apr 14 '19 at 15:30