9

For the following MWE

\documentclass{article}

\newcommand{\cmd}[5]{%
  \def\tA{#1}%
  \def\tB{#2}%
  \def\tC{#3}%
  \def\tD{#4}%
  \def\tE{#5}%

  \tA & \tB & \tC & \tD & \tE \\
}

\begin{document}
\begin{tabular}{ccccc}
  \cmd{1}{2}{3}{4}{5}
\end{tabular}
\end{document}

I keep getting the following error:

! Undefined control sequence.
\cmd ...}\def \tD {#4}\def \tE {#5}\par \tA & \tB 
                                                  & \tC & \tD & \tE \\ 
l.15   \cmd{1}{2}{3}{4}{5}

Why doesn't it work?

PS. The reason for using \def is that in my document I need to handle more than 9 parameters to the command, and thus apply this method.

gablin
  • 17,006
  • Can you show a real world example? Using more than nine arguments should be the very last resort; perhaps we can find a better way to input your text. – egreg Apr 07 '14 at 16:21
  • It's for a paper where we have a table with over 9 columns. We haven't decided upon the exact order of the columns, but we don't want to have to rearrange all the arguments for every row. So that's why we're using a macro which takes all these column values as arguments. – gablin Apr 07 '14 at 20:31
  • I said you that a better solution can be found. ;-) – egreg Apr 07 '14 at 21:08

2 Answers2

12

Cells inside a tabular form groups, so in your example the commands defined by \cmd are not available starting with the second cell. Solution: Use \gdef instead of \def in the definition of \cmd.

\documentclass{article}

\newcommand{\cmd}[5]{%
  \gdef\tA{#1}%
  \gdef\tB{#2}%
  \gdef\tC{#3}%
  \gdef\tD{#4}%
  \gdef\tE{#5}%

  \tA & \tB & \tC & \tD & \tE \\
}

\begin{document}
\begin{tabular}{ccccc}
  \cmd{1}{2}{3}{4}{5}
\end{tabular}
\end{document}
lockstep
  • 250,273
3

You can avoid using many arguments. Here's an implementation of your \cmd where you specify the arguments as a comma separated list; with \selectorder you can decide what order is used in the output.

Note that \cmd will happily accept any number of items in the list; all you need is to specify the correct number of columns in the tabular and precede it with the suitable \selectorder command. I demonstrated this with two tables with four and five columns respectively.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\cmd}{m}
 {
  \gablin_cmd:n { #1 }
 }

\NewDocumentCommand{\selectorder}{m}
 {
  \seq_gset_split:Nnn \g_gablin_order_seq { , } { #1 }
 }

\prop_new:N \l_gablin_arg_prop
\seq_new:N \l_gablin_output_seq
\seq_new:N \g_gablin_order_seq
\int_new:N \l_gablin_input_int

\cs_new_protected:Npn \gablin_cmd:n #1
 {
  % clear the variables' contents (it isn't really necessary)
  \prop_clear:N \l_gablin_arg_prop
  \seq_clear:N \l_gablin_output_seq
  \int_zero:N \l_gablin_input_int
  % map through the items in the argument
  \clist_map_inline:nn { #1 }
   {
    % the integer variable is used to number the items
    \int_incr:N \l_gablin_input_int
    % items are stored in a property list
    \prop_put:Nfn \l_gablin_arg_prop { \int_to_arabic:n { \l_gablin_input_int } } { ##1 }
   }
  % map through the items stating the order of items in columns
  \seq_map_inline:Nn \g_gablin_order_seq
   {
    % put the items in a new sequence
    \seq_put_right:Nx \l_gablin_output_seq
     {
      \prop_get:Nn \l_gablin_arg_prop { ##1 }
     }
   }
  % use the sequence, separating arguments with &
  \seq_use:Nn \l_gablin_output_seq { & }
 }

% we need a variant of \prop_put:Nnn store a number in the key
\cs_generate_variant:Nn \prop_put:Nnn { Nf }

\ExplSyntaxOff

\begin{document}

\selectorder{1,2,3,4}

\begin{tabular}{*{4}{c}}
\cmd{aa,ab,ac,ad} \\
\cmd{ba,bb,bc,bd} \\
\cmd{ca,cb,cc,cd} \\
\end{tabular}

\bigskip

\selectorder{5,4,3,2,1}

\begin{tabular}{*{5}{c}}
\cmd{aa,ab,ac,ad,ae} \\
\cmd{ba,bb,bc,bd,be} \\
\cmd{ca,cb,cc,cd,ce} \\
\end{tabular}

\end{document}

The setting defined by \selectorder will remain valid until countermanded by another choice and is global, so it doesn't matter if it's issued in a table environment. So this code is very flexible.

enter image description here

egreg
  • 1,121,712