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

3 Answers

up vote 10 down vote accepted

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).

share|improve this answer
    
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 '12 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 '12 at 21:44
add comment

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}
share|improve this answer
    
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. –  Peter Grill Jul 4 '12 at 17:28
    
What is the purpose of the \relax in your definition above? –  azetina Jul 4 '12 at 19:00
    
\relax terminates the e-tex \numexpr expression –  David Carlisle Jul 4 '12 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 –  David Carlisle Jul 4 '12 at 19:04
add comment

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