15

I would like to copy the row of a table, let say, n times, but unfortunately my sample below does not compile. It is my understanding that the \foreach command should copy what is in its argument but is not doing it here. I have looked at the error message in the compiler and I have an idea as to what may be causing it. I think it is how the table environment is constructed. I am thinking right now of enveloping the command as a group but I don't know how to do this. What is the best way to achieve this result? Some explanation will be appreciated.

\documentclass[letterpaper]{article}
\usepackage{amsmath,amssymb,lipsum}
\usepackage{tikz,calc}
\newcommand{\test}[1]{%
    \foreach \i in {1,...,#1}
    {%
    t1 & t2 \\%
    }}
\begin{document}
\begin{tabular}{cc}
\test{3}
\end{tabular}
\end{document}

3 Answers 3

17

The main problem is that \foreach works in a group, but it's not only that.

The simplest thing to do is to first build the table in a macro and then expand it:

\documentclass{article}
\usepackage{tikz}

\newcommand{\test}[1]{%
  \def\temp{}%
  \foreach \i in {1,...,#1}
    {%
    \expandafter\gdef\expandafter\temp\expandafter{\temp t1 & t2 \\}%
    }%
  \temp}

\begin{document}
\begin{tabular}{cc}
\test{3}
\end{tabular}
\end{document}

The \temp macro is initialized to empty and then augmented at each cycle; at the end it's expanded. The \gdef is necessary because of the implicit groups around the cycles.


With \test{3} what happens is essentially

\def\temp{}%
{\expandafter\gdef\expandafter\temp\expandafter{\temp t1 & t2 \\}}%
{\expandafter\gdef\expandafter\temp\expandafter{\temp t1 & t2 \\}}%
{\expandafter\gdef\expandafter\temp\expandafter{\temp t1 & t2 \\}}%
\temp

and everything takes place when TeX is still looking for the material in the first cell of the first row. The first line states that \temp expands to nothing; then the second line is executed: each \expandafter expands the second token after it; for the first two it's another \expandafter so we arrive at \temp. Hence the second line is equivalent to saying

{\gdef\temp{t1 & t2 \\}}

but when the same operation is performed in the third line the effect is

{\gdef\temp{t1 & t2 \\t1 & t2 \\}}

and at the fourth line it becomes

{\gdef\temp{t1 & t2 \\t1 & t2 \\t1 & t2 \\}}

The supplementary braces represent the implicit group that \foreach puts around the cycles. Thus \gdef is necessary because otherwise the redefinition of \temp would disappear at group end.

The presence of & tokens is not a problem, because TeX scans it between braces, so they aren't used for marking the end of a cell. This is an issue that, sometimes, bites someone.

At the end, \temp will produce the tokens

t1 & t2 \\t1 & t2 \\t1 & t2 \\

that will be seen properly by TeX for building the table.

A less readable definition, but which does exactly the same, would be

\makeatletter
\newcommand{\test}[1]{%
  \let\@temp\@empty
  \foreach \i in {1,...,#1}
    {%
    \g@addto@macro\@temp{t1 & t2 \\}%
    }%
  \@temp}
\makeatother

The compulsory LaTeX3 version:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\repeatrow}{mm}
 {
  \azet_repeat_row:nn { #1 } { #2 }
 }

\tl_new:N \l_azet_rows_tl
\cs_new_protected:Npn \azet_repeat_row:nn #1 #2
 {
  \tl_clear:N \l_azet_rows_tl
  \prg_replicate:nn { #1 } { \tl_put_right:Nn \l_azet_rows_tl { #2 \\ } }
  \tl_use:N \l_azet_rows_tl
 }
\ExplSyntaxOff

\begin{document}
\begin{tabular}{cc}
\repeatrow{3}{t1 & t2}
\end{tabular}
\end{document}

The working is very similar to the "classical" solution, but it uses \prg_replicate:nn instead of \foreach. The command is

\prg_replicate:nn { <integer expression> } { <code> }

and it evaluates the <integer expression> (so one might also call \repeatrow{3*5}{...}); then it repeats the <code> in the second argument as many times as specified in the first one.

This command is preceded by the analog of \def\temp{}: the token list variable \l_azet_rows_tl is cleared and the <code> is just "append the second argument to \azet_repeat_row:nn (which in turn is the "internal" version of \repeatrow). Then the contents of the token list variable is delivered for use (the analog of saying \temp in the first solution).

2
  • Could you shed more light into the \expandafter, \gdef and \temp commands as I was trying the \expandafter by trial and error and didnt get it to work? When can I use them and for what?
    – azetina
    Jul 4, 2012 at 15:22
  • I don't really understand Latex 3 but it is a nice implementation. Could you elaborate? I want to educate myself into the matter.
    – azetina
    Jul 4, 2012 at 21:44
11

You don't really need a for-each macro for this, you just need to take care that your loop counter and the groups from the table cells interact correctly.

The following produces the three row table without any large (or small) package overhead.

\documentclass{article}

\newcommand{\test}[1]{%
 t1 & t2 \\
\ifnum#1>1 
  \expandafter\test\expandafter{\numexpr#1-1\expandafter\relax\expandafter}\fi
}

\begin{document}
\begin{tabular}{cc}
\test{3}
\end{tabular}
\end{document}
4
  • While I can almost follow the \expandafters in @egreg's solution, I don't what kind of magic is going here with the last two uses of \expandafter. Jul 4, 2012 at 17:28
  • What is the purpose of the \relax in your definition above?
    – azetina
    Jul 4, 2012 at 19:00
  • \relax terminates the e-tex \numexpr expression Jul 4, 2012 at 19:02
  • @PeterGrill the last two are stepping over to complete the \fi before \test is executed so you don't get a build up of pending \fi on the input stack Jul 4, 2012 at 19:04
3

Here is an alternative using Latex 3,

\documentclass[letterpaper]{article}
\usepackage{expl3}

\ExplSyntaxOn
\cs_new_eq:NN \Copy \prg_replicate:nn
\ExplSyntaxOff

\begin{document}
\begin{tabular}{cc}
\Copy{4}{t1 & t2 \\}
\end{tabular}
\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .