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.

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}

output of code

share|improve this question
add comment

4 Answers

up vote 11 down vote accepted

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}
share|improve this answer
add comment

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.

\@foris a no developable loopso 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}
share|improve this answer
add comment

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}
  \toks@={\@gobble}%
  \@for\next:=#1\do
    {\toks@=\@xp{\the\@xp\toks@\@xp\\\@xp\text\@xp{\next}}}%
  \the\toks@
  \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

\toks@=\expandafter{\the\expandafter\toks@\next}

would have sufficed. Initializing \toks@ 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. :)

share|improve this answer
add comment

I believe the reason you're getting a fifth, empty row when generating the column vector via the for-loop 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}
share|improve this answer
    
Thanks 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. :-)) –  Alan Munn Nov 16 '11 at 2:54
    
I had a look at the definition of the \@for command in the LaTeX kernel (file latex.ltx, beginning on row 859) to see if I could figure out why the loop form creates an extra row whereas the non-loop form does not. However, I must say I can't penetrate the dense, uncommented code in that file. :-( –  Mico Nov 16 '11 at 3:41
    
I 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. –  Alan Munn Nov 16 '11 at 3:42
    
Your first question: Well, there's a \\ after C, then a D 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/not-yet-understood) reason for why there's no blank row in the non-loop creation of the column vector... –  Mico Nov 16 '11 at 3:50
    
Right, 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.) –  Alan Munn Nov 16 '11 at 3:59
add comment

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.