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.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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{...} 
share|improve this question
    
Note that \repeat is already defined by LaTeX as end-macro for \loop. – Martin Scharrer Apr 19 '11 at 19:34
up vote 25 down vote accepted

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

share|improve this answer
    
Ah, I should have known that LaTeX3 is having something like this. I coded something by myself and just saw your post. – Martin Scharrer Apr 19 '11 at 19:56
    
Note that while this seems like a overkill-approach, it should be (much?) more efficient than the simpler looping code proposed in other answers. – Will Robertson Apr 20 '11 at 9:20
    
As @Will says, this approach scales well (I use it for testing purposes often with 100k repetitions). – Joseph Wright Apr 20 '11 at 9:28
    
The important point to notice about the code is that it replicates for each power of ten. So as the number gets very big, rather than lots of single repetitions each 'level' requires only one pass. – Joseph Wright Apr 20 '11 at 9:56
2  
However, for huge number of repetitions, since all the repetitions are held in TeX's memory, we can overflow it. A solution in that case is \prg_replicate:nn {10000}{\prg_replicate:nn {10000}{...}}. Not needed often. – Bruno Le Floch May 13 '11 at 8:41

You can use the \foreach-command from PGF/TikZ.

\documentclass{minimal}
\usepackage{pgffor}
\newcommand{\cmd}{-x-}
% to provide your syntax
\newcommand{\Repeat}[2]{% \repeat already defined
    \foreach \n in {1,...,#1}{#2}
}
\begin{document}
\foreach \n in {1,...,4}{\cmd}

\Repeat{6}{\cmd}
\end{document}

For more information see the pgfmanual.pdf, section 56, pp. 504 an following.

There’s also a TeX-Way see e.g. this page (in german …)

share|improve this answer
3  
pgfs \foreach has the drawback that the command is executed in a group, which might be a big problem or none at all depending on the application. BTW: there is no reason the write {} after \cmd inside the loop, except if you have it as a placeholder for a possible argument (then you should write it as {...} as the OP did). – Martin Scharrer Apr 19 '11 at 19:33
1  
@MartinScharrer There’s no special reason why I used the {}. You’re right an I edited my post. Could you please outline a situation where the \foreach-group causes problems? – Tobi Apr 19 '11 at 20:38
1  
All assignments done in the loop will be executed in their own local group, which could have serious side effects depending on the code. Because you never known what code the user will use it is best to avoid these situations. – Martin Scharrer Apr 19 '11 at 21:06
    
@MartinScharrer Thank’s. Maybe I remember that in case of getting problem with \foreachif not I’ll be back to ask here ;-) – Tobi Apr 19 '11 at 21:57

Here some implementation I came up with which doesn't need any extra package. It uses \numexpr to avoid counters and is fully expandable.

\documentclass{article}

\makeatletter
\newcommand{\Repeat}[1]{%
    \expandafter\@Repeat\expandafter{\the\numexpr #1\relax}%
}

\def\@Repeat#1{%
    \ifnum#1>0
        \expandafter\@@Repeat\expandafter{\the\numexpr #1-1\expandafter\relax\expandafter}%
    \else
        \expandafter\@gobble
    \fi
}
\def\@@Repeat#1#2{%
    \@Repeat{#1}{#2}#2%
}
\makeatother

\begin{document}

\Repeat{0}{test }

\Repeat{1}{test }

\Repeat{2}{test }

\Repeat{3}{test }

\Repeat{4}{test }

\Repeat{5}{test }

\edef\TEST{\Repeat{5}{test }}
\texttt{\meaning\TEST}

\end{document}
share|improve this answer
    
If you look at the LaTeX3 implementation, it's expandable even without needing e-TeX. This is some clever code that has been around for many years. – Joseph Wright Apr 19 '11 at 20:33
    
@Joseph: I have a really hard time reading the expl3 code, but it looks like it needs e-TeX to me. It uses \int_eval:w a.k.a. \numexpr. – TH. Apr 20 '11 at 7:42
    
@TH. The expl3 implementation does indeed need \numexpr, as that makes the nature of the 'number' you give be more flexible. However, the original version of this approach just uses \number, and thus no e-TeX. Later on today I'll post the code 'translated' to plain TeX as a separate answer. – Joseph Wright Apr 20 '11 at 8:09
    
@TH. I've added the plain TeX code to my answer, avoiding e-TeX but explaining why it is used for the expl3 version. – Joseph Wright Apr 20 '11 at 8:34
    
@Joseph: I see now, that's very clever! Thanks. (One of these days, I really just need to learn expl3.) – TH. Apr 20 '11 at 8:49

Plain and simple (pun intended):

\def\foo{keke}
\def\bar#1#2{\count0=#1 \loop \ifnum\count0>0 \advance\count0 by -1 #2\repeat}
\bar3\foo % results in kekekekekeke
\bye

Token list registers expand more quickly, so if it suits you, you could also do:

\newtoks\foo \foo={keke}
\def\bar#1#2{\count0=#1 \loop \ifnum\count0>0 \advance\count0 by -1 \the#2\repeat}
\bar3\foo % results in kekekekekeke
\bye

Repeating in an expendable way using e-tex additions (from http://www.tug.org/TUGboat/tb29-2/tb92jackowski.pdf):

\def\foo{keke}
\def\gobbleone#1{}
\long\def\replicate#1#2{% 
  \ifnum\numexpr#1>0 
    #2\expandafter\replicate\expandafter 
    {\number\numexpr#1-1\expandafter}% 
  \else 
    \expandafter\gobbleone 
  \fi{#2}}
\replicate3\foo % results in kekekekekeke
\bye
share|improve this answer
    
Yes, but not expandable. Ok, it isn't really necessary in the majority of the cases. – Martin Scharrer Apr 19 '11 at 20:54
    
What does it mean not being expandable? – Christian Lindig Apr 20 '11 at 5:52
    
Christian forgot to notify @Martin I guess, since I don't know the answer to that question. – morbusg Apr 20 '11 at 7:06
    
@Christian: Something is expandable if you can use it inside an \edef or \write an TeX converts it fully to what you want. Assignments are not expandable, and so a loop using a count will not turn into a series of repeated commands inside an \edef. – Joseph Wright Apr 20 '11 at 7:06
    
@Christian: I thought that the general question had been asked, but cannot find it. You might wish to ask about expandability in general, and those of us who understand it can try to explain! – Joseph Wright Apr 20 '11 at 7:08

multido has a simple interface for replication:

enter image description here

\documentclass{article}
\usepackage{multido}
\newcommand{\cmd}{-x-}
\newcommand{\Repeat}{\multido{\i=1+1}}
\begin{document}

\Repeat{6}{\cmd}
\end{document}
share|improve this answer

Here is an example with loop and newcommand:

\documentclass{article}
\newcounter{z}
\newcommand\y[2]{
  \loop \ifnum\value{z} < #1
    #2%
    \stepcounter{z}%
  \repeat
}
\begin{document}
\y{10}{Hello}
\end{document}
share|improve this answer
    
The request is to repeat a command – Andrew Swann Mar 20 at 15:11
    
Only the simplest commands - e.g. if the new command defines other commands the grouping is not equivalent. – Andrew Swann Mar 20 at 15:23
    
Isn't this the same as the first suggestion in @morbusg's answer? – clemens Mar 20 at 15:27

Of course, the simple answer to the OP is: use \loop. But there are more codes here signed as "clever", if the loop is done only at expand processor level. And more "clever" codes here do this without using of eTeX primitives.

So, I give two codes here. You can explore them from "cleverness" point of view:).

First code uses known trick with \romannumeral #1000 which expands to #1 "em"s and then we do loop over these "em"s over input stream. The main difference from the similar code presented here by @Joseph is that we needn't to read whole long sequence of "em"s again and again:

\def\replicate#1{\expandafter\repU\expandafter{\romannumeral\number#1000}}
\def\repU#1#2{\repV{#2}#1;}
\def\repV#1#2{\ifx#2;\else#1\fihere\repV{#1}\fi}
\def\fihere#1\fi{\fi#1}

\message{\replicate{27}{abc}}
\bye

The second code is inspired by second code presented here by @Joseph where each decimal digit is processed individually. The code (in the accepted answer) uses nested \csnames. I do the same without nested \csnames and the code is more compact. Of course, it works at expand processor level without any need of eTeX primitives:

\def\replicate#1{\expandafter\repA\number#1;;}
\def\repA#1#2;#3;{\ifx;#2;\repB#1#3\fi \repA#2;#1#3;}
\def\repB#1\fi#2;#3;{\fi\repC{#1}}
\def\repC#1#2{\repD{#2}#1;}
\def\repD#1#2{\ifx#2;\else \repE{#1}#2\fi}
\def\repE#1#2\fi{\fi \repF#2{#1}\repD{\repF{10}{#1}}}
\def\repF#1#2{\ifcase#1 \or#2\or#2#2\or#2#2#2\or#2#2#2#2\or#2#2#2#2#2\or
   #2#2#2#2#2#2\or#2#2#2#2#2#2#2\or#2#2#2#2#2#2#2#2\or
   #2#2#2#2#2#2#2#2#2\or#2#2#2#2#2#2#2#2#2#2\fi}

\message{\replicate{27}{abc}}
\bye
share|improve this answer
    
My comment about eTeX was probably misleading: I've removed it (you need eTeX if you want to accept integer expressions for the number of repeats, not for the core idea of making copies). – Joseph Wright Mar 21 at 10:20
    
nice but it should be pointed out this doesn't expand fully under \romannumeral-`0. – jfbu Mar 22 at 22:24

I tried an alternative to the most clever chained \csname's from @JosephWright expl3 code, and for a while had something a bit simpler looking. But I had a problem to not needlessly generate a last 10^n copies of #1 to be then discarded. The work-around makes the code here longer looking than the one of expl3... and is definitely less clever.

eTeX is used only to allow input to be an expression: else replace \the\numexpr at the start by \number.

I think this should be circa the same as expl3 code in terms of efficiency (a bit not as good, though, a bit more token fetching). They produce the same result, except that the code here, in case of negative replication, stops immediately whereas the code posted by Joseph does generate abs(N) copies first.

Also, I have left the initial \romannumeral out, the macro is to be called as \romannumeral\replicate{N}{stuff}.

\catcode`@ 11

\def\signfork #10-#2#3\krof {#2}
\chardef\z@ 0

\def\replicate   #1{\expandafter\replicate@a\the\numexpr #1;Q.}%
\def\replicate@a #1{\signfork
                      #1-\replicate@none
                      0#1\replicate@neg
                       0-\replicate@b
                    \krof #1%
                   }%
\long\def\replicate@none 0;Q.#1{\z@}
\long\def\replicate@neg #1;Q.#2{\z@\Error@NegativeReplicationAttemptedNoneDone}

\def\replicate@b #1#2;{%
     \if\relax#2\relax\replicate@c\fi
     \replicate@b #2;#1%
}%

\def\replicate@c\fi\replicate@b;#1{\fi\csname replicate@dolast@#1\endcsname }%
\expandafter\def\csname replicate@dolast@0\endcsname #1#2.%
     {\csname replicate@do@#1\endcsname #2.}%
\long\expandafter\def\csname replicate@dolast@1\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3}%
\long\expandafter\def\csname replicate@dolast@2\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3#3}%
\long\expandafter\def\csname replicate@dolast@3\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3#3#3}%
\long\expandafter\def\csname replicate@dolast@4\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3#3#3#3}%
\long\expandafter\def\csname replicate@dolast@5\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3#3#3#3#3}%
\long\expandafter\def\csname replicate@dolast@6\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@dolast@7\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@dolast@8\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@dolast@9\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3}#3#3#3#3#3#3#3#3#3}%

\long\def\replicate@do@Q .#1{\z@}%

\long\expandafter\def\csname replicate@do@0\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}}%
\long\expandafter\def\csname replicate@do@1\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@do@2\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@do@3\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@do@4\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@do@5\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@do@6\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@do@7\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@do@8\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3}%
\long\expandafter\def\csname replicate@do@9\endcsname #1#2.#3%
     {\csname replicate@do@#1\endcsname #2.{#3#3#3#3#3#3#3#3#3#3}#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3}%

\catcode`@ 12

\def\odef #1{\expandafter\def\expandafter #1\expandafter}%

\odef\z{\romannumeral\replicate{0}{\x}}

\show\z

\odef\z{\romannumeral\replicate{-3}{\x}}

\show\z

\odef\z{\romannumeral\replicate{27}{\x}}

\show\z

\odef\z{\romannumeral\replicate{999}{1}}

\show\z
\bye
share|improve this answer

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.