Understanding a \@for loop

2,028

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.

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

Solution 4

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:
2,028

Related videos on Youtube

Alan Munn
Author by

Alan Munn

Updated on July 15, 2020

Comments

  • Alan Munn
    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}
    

    output of code

  • Alan Munn
    Alan Munn almost 11 years
    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. :-))
  • Mico
    Mico almost 11 years
    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. :-(
  • Alan Munn
    Alan Munn almost 11 years
    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.
  • Mico
    Mico almost 11 years
    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...
  • Alan Munn
    Alan Munn almost 11 years
    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.)