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.

How can I access the i'th argument of a \newcommand declaration via an iteration variable?

Assume I want a command \foo like:

\newcommand{\barr}[1]{argument 1 is: #1}

\newcommand{\foo}[6]{
    \foreach \i in {1,...,6}
        \barr{#\i}; %this does not work. \barr{#1}, \barr{#6} do work
}

EDIT: As requested a bit of background. I want a command like \foo{1}{2}{5}{0}{1}{2} to paint 1 ball in the first section, 2 in the second, 5 in the third and so on. Everything works fine, the only thing I was missing was to access the i'th parameter in a convenient way.

share|improve this question
    
I'm not sure that I recognize which \foreach you use since there're more of them. Could you please convert your code into a Minimal (non-)Working Example? –  tohecz Jan 15 at 16:14
    
    
@StevenB.Segletes: But I think that the problem remains: how do I generate \argxiii from \i? –  mort Jan 15 at 16:31
    
See my answer, and let me know if \whiledo is acceptable, or if you require \foreach. –  Steven B. Segletes Jan 15 at 16:43
    
If you'd add something about what's your aim, it would be possible to tell more. –  egreg Jan 15 at 16:47
show 2 more comments

4 Answers

up vote 4 down vote accepted

This uses \whiledo instead of \foreach which may or may not be acceptable to the OP.

\documentclass{article}
\usepackage{stringstrings}
\newcounter{index}
\newcommand{\barr}[2]{argument #1 is: #2\par}
\newcommand\foo[1]{%
  \getargs{#1}%
  \setcounter{index}{0}%
  \whiledo{\theindex < \narg}{%
    \stepcounter{index}%
    \barr{\theindex}{\csname arg\romannumeral\theindex\endcsname}%
  }%
}
\begin{document}
\foo{A B C D EE F GGG H I JJJ K FinalArgument}
\end{document}
share|improve this answer
    
\whiledo is ok in my case. And this solution rocks! –  mort Jan 15 at 16:50
1  
@mort The \getargs macro in stringstrings can be somewhat slow. A much faster version is \getargsC in the readarray package. So if you change the \usepackage and add a C to the macro name, speed will improve. –  Steven B. Segletes Jan 15 at 17:17
    
ok, thanks! I'll change that. –  mort Jan 15 at 18:43
add comment

You can't specify a macro that way; the #1, #2 and so on must be literally present at definition's time, because they represent placeholders.


I don't see why limiting to six: you'll probably need the same for five or eight.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\foo}{ O{,} m}
 {
  \mort_add_bar:nn { #1 } { #2 }
 }

\seq_new:N \l_mort_input_seq
\seq_new:N \l_mort_output_seq
\cs_new_protected:Npn \mort_add_bar:nn #1 #2
 {
  % split the input at the comma (or what's in the optional argument)
  \seq_set_split:Nnn \l_mort_input_seq { #1 } { #2 }
  % clear the output section
  \seq_clear:N \l_mort_output_seq
  % put each item inside \bar{...}
  \seq_map_inline:Nn \l_mort_input_seq
   {
    \seq_put_right:Nn \l_mort_output_seq { \bar{ ##1 } }
   }
  % output the sequence, separated by semicolons
  \seq_use:Nn \l_mort_output_seq { ; }
 }
\ExplSyntaxOff

\begin{document}
$\foo{a,b,c}$

% just to show that you can change the
% delimiter and have as many items as you wish
$\foo[.]{a.b.c.e.f.g.h.i}$ 
\end{document}

enter image description here

For drawing a number of objects, here's a possible solution:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\foo}{ O{,} m }
 {
  \mort_add_bar:nn { #1 } { #2 }
 }

\seq_new:N \l_mort_input_seq
\cs_new_protected:Npn \mort_add_bar:nn #1 #2
 {
  \seq_set_split:Nnn \l_mort_input_seq { #1 } { #2 }
  \seq_map_inline:Nn \l_mort_input_seq
   {
    \mort_draw_balls:n { ##1 }
   }
 }
\cs_new_protected:Npn \mort_draw_balls:n #1
 {
  /
  \prg_replicate:nn { #1 } { \textbullet }
  /
 }

\ExplSyntaxOff

\begin{document}
\foo{1,2,5,0,1,2}

% just to show that you can change the
% delimiter and have as many items as you wish
\foo[-]{1-3-4}
\end{document}

enter image description here

share|improve this answer
1  
Awesome solution! –  mort Jan 15 at 16:28
add comment

egreg's and Steven B. Segletes's solutions are of course awesome. However, if one has a fixed number of arguments it seems a bit over the top.

As an alternative, this works too:

\newcommand{\bar}[1]{argument 1 is: #1}

\newcommand{\foo}[6]{
\foreach \i/\j in {1/#1,2/#2,3/#3,4/#4,5/#5,6/#6}   
    \putinbin{\i}{\j};
}
share|improve this answer
add comment

I don't think that TeX-core allows this in a simple way. The simplest way would be probably the following, but it's neither nice nor efficient since you have to put the correct number of terms (otherwise TeX-core complains about invalid parameter).

\newcommand{\bar}[1]{argument 1 is: #1}

\newcommand{\foo}[6]{
    \foreach \i in {1,...,6}
        \bar{\ifcase\i\or#1\or#2\or#3\or#4\or#5\or#6\fi};
}
share|improve this answer
1  
Hm, would be simpler and nicer to just write \bar six times... –  mort Jan 15 at 16:16
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.