[Tex/LaTex] Repeat command n times

macrosprogramming

Is it possible to define a command, which repeats the following command n-times? Call it for example \Repeat, then

\Repeat[4] \command{...} 

should be equivalent to

\command{...} \command{...} \command{...} \command{...} 

Best Answer

This can be done in an expandable form using \csname. I would personally use the 'pre-packed' version in expl3:

\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_eq:NN \Repeat \prg_replicate:nn
\ExplSyntaxOff
\begin{document}
\Repeat{4}{\command{...}}
\end{document}

For those who would code by hand, the basic approach (originally by David Kastrup, modified somewhat by the rest of the team) is

\catcode `\@ = 11\relax
\long\def\replicate#1{%
  \romannumeral
    \expandafter\replicate@first@aux\number#1%
      \endcsname
}
\long\def\replicate@first@aux#1{%
  \csname replicate@first@#1\replicate@aux
}
\chardef\rm@end=0 %
\long\expandafter\def\csname replicate@first@-\endcsname
  #1{\rm@end\NegativeReplication}
\long\expandafter\def\csname replicate@first@0\endcsname
  #1{\rm@end}
\long\expandafter\def\csname replicate@first@1\endcsname
  #1{\rm@end #1}
\long\expandafter\def\csname replicate@first@2\endcsname
  #1{\rm@end #1#1}
\long\expandafter\def\csname replicate@first@3\endcsname
  #1{\rm@end #1#1#1}
\long\expandafter\def\csname replicate@first@4\endcsname
  #1{\rm@end #1#1#1#1}
\long\expandafter\def\csname replicate@first@5\endcsname
  #1{\rm@end #1#1#1#1#1}
\long\expandafter\def\csname replicate@first@6\endcsname
  #1{\rm@end #1#1#1#1#1#1}
\long\expandafter\def\csname replicate@first@7\endcsname
  #1{\rm@end #1#1#1#1#1#1#1}
\long\expandafter\def\csname replicate@first@8\endcsname
  #1{\rm@end #1#1#1#1#1#1#1#1}
\long\expandafter\def\csname replicate@first@9\endcsname
  #1{\rm@end #1#1#1#1#1#1#1#1#1}
\def\replicate@aux#1{%
  \csname replicate@#1\replicate@aux
}
\long\expandafter\def\csname replicate@\endcsname#1{\endcsname}
\long\expandafter\def\csname replicate@0\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}}
\long\expandafter\def\csname replicate@1\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1}
\long\expandafter\def\csname replicate@2\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1}
\long\expandafter\def\csname replicate@3\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1}
\long\expandafter\def\csname replicate@4\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1}
\long\expandafter\def\csname replicate@5\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1}
\long\expandafter\def\csname replicate@6\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1}
\long\expandafter\def\csname replicate@7\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1}
\long\expandafter\def\csname replicate@8\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1#1}
\long\expandafter\def\csname replicate@9\endcsname
  #1{\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1#1#1}
\catcode `\@ = 12\relax
\edef\test{\replicate{20}{abc}}
\show\test
\bye

In the expl3 version, the \number#1 is (effectively) replaced by \number\numexpr#1\relax, which allows the 'number' used to be a calculation. If you try a negative number, the deliberately-undefined control sequence raises an error as part of the expansion, rather than having some odd error later.


A second expandable approach is to use \romannumeral, for example

\catcode `\@ = 11\relax
\def\replicate#1{%
  \expandafter\replicate@aux\romannumeral\number #1000Q{}
}
\def\replicate@aux#1{\csname replicate@aux@#1\endcsname}
\long\def\replicate@aux@m#1Q#2#3{\replicate@aux#1Q{#2#3}{#3}}
\long\def\replicate@aux@Q#1#2{#1}
\edef\test{\replicate{5}{a}}
\show\test
\bye

This is clearer to code than the \csname approach, but is effectively a loop again and so gets slow for large numbers of repetitions.

Related Question