Understanding a \@for loop
Solution 1
As Altermundus said, you cannot add extra {}
or \relax
or other invisible material after the last row of the tabular
. However, there is some extra material added after \@for
. The implementation of \@for
is not very good for this.
Since the \@for
in LaTeX2e kernel has restrictions, I suggest \forcsvlist
from etoolbox
:
\documentclass{article}
\usepackage{amsmath}
\usepackage{etoolbox}
\def\addrow#1{\text{#1}\\}
\newcommand{\fbun}[1]
{\ensuremath{\left[\begin{array}{c}
\forcsvlist\addrow{#1}%
\end{array}\right]}}
\begin{document}
$\left[\begin{array}{c}
A\\
B\\
C\\
D\\
\end{array}\right]$
\fbun{A,B,C,D}
\end{document}
Solution 2
The problem is that TeX finds something following the last \\
which starts a new row (it's neither \noalign
nor \crcr
that wouldn't).
A solution might be to use a token register: we develop the loop while in the first cell, so there's no problem of \xx
not being defined any more after TeX has seen \\
(or &
).
\usepackage{amsmath}
\makeatletter
\newcommand{\fbun}[1]{%
\begin{bmatrix}
\[email protected]={\@gobble}%
\@for\next:=#1\do
{\[email protected]=\@xp{\the\@xp\[email protected]\@xp\\\@xp\text\@xp{\next}}}%
\the\[email protected]
\end{bmatrix}}
\makeatother
I've used \@xp
(from amsmath) that's a shorthand for \expandafter
; if the \text
around the entry wasn't required, then
\[email protected]=\expandafter{\the\expandafter\[email protected]\next}
would have sufficed. Initializing \[email protected]
to \@gobble
has the effect that the first \\
is swallowed.
Instead of array
I've used bmatrix
(change it if you like) and, of course, I deleted \ensuremath
as the first step. :)
Solution 3
In "User's Guide and Reference Manual" Leslie Lamport writes page 45:
There must be no
&
after the last item in a row and no\\
after the last row.
$\left[\begin{array}{c}
A\\
B\\
C\\
D\\{}%
\end{array}\right]$
This code gives a new line with an empty group. Each cell of an array is in a group.
\@for
is a no developable loop
so you need to write something like
\fbun{A,B,C}
D
or you can create a developable loop
but it's more complicated :
\makeatletter
\newcommand*{\For}[1]{\noalign{\gdef\@Do##1{#1}}\@For}
\newcommand*{\@For}[3]{%
\unless\ifnum#1 \ifnum#3>0 >\else <\fi #2
\@Do{#1}%
\expandafter\@For\expandafter{\number\numexpr#1+#3}{#2}{#3}%
\fi
}
\makeatother
$\left[\begin{array}{c}
\For{\@Alph{#1}\\}{1}{4}{1}
\end{array}\right]$
\For
is a developable loop
for example, you can try :
\begin{tabular}{ll}
\For{A number & #1\\}{1}{20}{1}
\end{tabular}
Solution 4
I believe the reason you're getting a fifth, empty row when generating the column vector via the forloop is that the fourth element (like the three before it) gets a \\
affixed to it; this instruction creates a new row which ends up being blank since there's no further content to create.
A (not very elegant) solution would be to redefine \fbun
to take two arguments, as follows:
\newcommand{\fbun}[2]
{\ensuremath{\left[\begin{array}{c}
\@for\xx:=#1\do {\text{\xx}\\} #2
\end{array}\right]}}
and to invoke it as
\fbun{A,B,C}{D}
Related videos on Youtube
Alan Munn
Updated on July 15, 2020Comments

Alan Munn over 2 years
I'm having trouble with a
\@for
loop. I've got a macro that takes a comma delimited list and puts each element into a row of an array. When I do this using a\@for
loop, I get an extra row that I don't understand. I can manually get rid of it with a negative space, (as in the commented line below) but that can't be the right way to do it, so I must be doing something wrong. Here's a minimal example. For comparison, if I construct what I expect the result of the loop to be manually, the extra row doesn't appear.\documentclass{article} \usepackage{amsmath} \makeatletter \newcommand{\fbun}[1] {\ensuremath{\left[\begin{array}{c} \@for\xx:=#1\do {\text{\xx}\\} % \\ [2.75ex] % why is this required? \end{array}\right]}} \makeatother \begin{document} $\left[\begin{array}{c} A\\ B\\ C\\ D\\ \end{array}\right]$ % same array, but generated by a macro \fbun{A,B,C,D} \end{document}

Alan Munn almost 11 yearsThanks for your answer. I also thought that the final \\ was causing the problem, but I don't understand why the manually created version of the array, which also has the extra \\ doesn't have a fifth row. (As for your workaround, I think I prefer mine. :))

Mico almost 11 yearsI had a look at the definition of the
\@for
command in the LaTeX kernel (filelatex.ltx
, beginning on row 859) to see if I could figure out why the loop form creates an extra row whereas the nonloop form does not. However, I must say I can't penetrate the dense, uncommented code in that file. :( 
Alan Munn almost 11 yearsI seem to recall having looked at that code too. :) Some more puzzles: if the extra row comes from the final \\, why isn't there a blank row between the C and D in your version of the command? Also, if you add an extra \\ after
#2
in your command, you don't get an extra row. 
Mico almost 11 yearsYour first question: Well, there's a
\\
afterC
, then aD
is inserted as #2, so I don't see why there should be an empty row. (Incidentally, I did try out my code before posting the answer, to be sure there was no longer an extra row...) Re question 2: I can't tell for sure, but presumably it's for the same (and currently unknown/notyetunderstood) reason for why there's no blank row in the nonloop creation of the column vector... 
Alan Munn almost 11 yearsRight, but by hypothesis, the loop always should introduce an extra row at the end of the loop, so it's not clear to me why you shouldn't get two \\'s after the C, since you seem to get two \\'s after my version of the loop. That's what's so weird about the problem. (BTW, if you try to make the \\'s code the markup gets confused.)