5

Is there a way to run a command on a range of consecutive integers (say, 11, 12, 13, 14, 15), specifying only the first and last numbers (11 and 15)? Basically I'm looking for the general LaTeX equivalent of tikz's \foreach \x in {11,…,15}.

In the MWE below (using etoolbox), \forcsvlist\mycommand{11,12,13,14,15} correctly runs \mycommand on each of the four inputs, and \myrange{11}{15} indeed expands to 11,12,13,14,15. But putting them together \forcsvlist\mycommand{\myrange{11}{15}} doesn't work. I think it comes down to order of expansion, which is way over my head.

\documentclass{article}
\usepackage{amsmath, etoolbox}
\newcommand\mycommand[1]{\boxed{#1} }
\newcounter{mycounter}
\newcommand\myrange[2]{
    \defcounter{mycounter}{#1}
    \themycounter%
    \whileboolexpr
        {test {\ifnumless{\themycounter}{#2}}}
        {\stepcounter{mycounter},\themycounter}
    }
\begin{document}
\forcsvlist\mycommand{11,12,13,14,15}
does not equal
\forcsvlist\mycommand{\myrange{11}{15}}
\end{document}

I've looked at Loop Multi-Contingency using etoolbox, Print all elements of a working array created with etoolbox package, and Remove extra curly braces, but couldn't figure out how to apply them to this situation.

Matt S
  • 267
  • You are defining and setting counters in your \myrangemacro -- this can't be expandable. There might be more issues, but I can't check right now –  Feb 19 '18 at 20:45
  • Similar (?) https://tex.stackexchange.com/a/360959/31729 –  Feb 19 '18 at 20:59

3 Answers3

7

It is just as easy to loop without any specific package code in this case. enter image description here

\documentclass{article}
\usepackage{amsmath}
\newcommand\mycommand[1]{\boxed{#1} }

\makeatletter
\newcommand\zz[3]{%
 #1{#2}%
 \ifnum#2=\numexpr#3\relax\expandafter\@gobblefour\fi
 \zz#1{\the\numexpr#2+1\relax}{#3}%
 }
\makeatother

\begin{document}


\zz\mycommand{11}{15}
\end{document}
David Carlisle
  • 757,742
  • you get nested \numexpr which numexperts usually remove by suitable \expandafter ;-) (this may also surprise macro \mycommand if the latter parses in some way its argument and chokes on ten nested \numexpr's) –  Feb 20 '18 at 13:41
  • @jfbu I wondered about adding more expandafter but thought it would obscure the main point, it's not actually wrong is it? – David Carlisle Feb 20 '18 at 13:48
  • nothing wrong ;-) –  Feb 20 '18 at 15:02
4

Optionally providing also the step; the \int_step_function:nnnN macro takes as argument the starting point, the step, the final point and finally the one parameter macro to which the current value is passed as argument.

\documentclass{article}
\usepackage{xparse}

\newcommand\mycommand[1]{\fbox{#1} }

\ExplSyntaxOn
\NewDocumentCommand{\forrange}{mO{1}mm}
 {
  \int_step_function:nnnN { #1 } { #2 } { #3 } #4
 }
\ExplSyntaxOff

\begin{document}

\forrange{11}{15}{\mycommand}

\forrange{11}[4]{27}{\mycommand}

\forrange{15}[-1]{11}{\mycommand}

\end{document}

enter image description here

egreg
  • 1,121,712
4
\documentclass{article}
\usepackage{xinttools}

\newcommand\mycommand[1]{\fbox{#1} }

\newcommand\forrange[4][1]%
    {\xintFor*##1in{\xintSeq[#1]{#2}{#3}}\do{#4{##1}}}

\begin{document}

\forrange{11}{15}{\mycommand}

\forrange[4]{11}{27}{\mycommand}

\forrange[-1]{15}{11}{\mycommand}

\end{document}

Now I picked over that abstraction from another authoritative answer. For everyday use you can also use

\xintFor #1 in {99, 37, -53, 'zouzou'}\do{ whatever }

and replace #1 by ##1 if inside a macro definition.

enter image description here