7

I want to fill a table with a dynamic (calculated) amount of columns. The column should be filled with a value which the user should provide comma separated. I therefore tried to use forcsvloop, but I must have made some mistakes, as I got a strange error:

Undefined control sequence ^^I\entry{5,6,7}

with example

\documentclass{article} 
\usepackage{etextools}

%Create a table with a specific amount of columns
\newenvironment{vartab}[1]
{
    \begin{tabular}{ |c@{} *{#1}{r|} } \hline
}{
    \end{tabular}
}

\newcommand{\entry}[1]{
    \forcsvloop{#1}\do{
        & ##1
    }\\ \hline
}

\begin{document}

\begin{vartab}{3}
    & 2 & 3 & 4 \\\hline
    \entry{5,6,7}
\end{vartab}

\end{document}

Do you know what the problem might be?

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
muffel
  • 1,565
  • 1
  • 13
  • 24
  • Note that TeX is not “free form” and end-of-lines are significant: they're translated into spaces that may or may not appear in the output; several of your end-of-lines do appear in the output. – egreg Aug 13 '13 at 10:15
  • @egreg What kind of "end-of-lines" do you mean, the manual ones ("\") or the raw newline characters ("\n") in my example? – muffel Aug 13 '13 at 10:18
  • The raw newlines. For instance, you get spaces before and after the table, which you can check with X\begin{vartab}{3}&2&3&4\\\hline\end{vartab}X – egreg Aug 13 '13 at 11:19

2 Answers2

7

A simpler way to do this is using an auxillary macro, to simplify expansion:

Sample output

\documentclass{article} 
\usepackage{etextools}

%Create a table with a specific amount of columns
\newenvironment{vartab}[1]
{
    \begin{tabular}{ |c@{} *{#1}{r|} } \hline
}{
    \end{tabular}
}

\newcommand{\myformat}[1]{& #1}

\newcommand{\entry}[1]{
  \edef\result{\csvloop[\myformat]{#1}}
  \result \\ \hline
}

\begin{document}


\begin{vartab}{3}
    & 2 & 3 & 4 \\\hline
    \entry{5,6,7}
\end{vartab}

\end{document}

As a completely different approach note that tabular is built on top of the tex primitive \halign that builds tables row by row. This primitive has an vertical analogue \valign that works columnwise:

Sample output

\documentclass{article}

\begin{document}

\valign{\hrule\vskip 2pt plus 1fil\hbox{\strut\quad #\quad}\vfil&
\hrule\vskip 2pt plus 1 fil \hbox{\strut\quad #\quad}
\vskip 1pt plus 1fil\hrule\cr
\noalign{\vrule}
2&5\cr
\noalign{\vrule}
3&6\cr
\noalign{\vrule}
4&7\cr
\noalign{\vrule}}

\end{document}
Andrew Swann
  • 95,762
5

You're trying to begin the loop in a cell and end it in another, which isn't possible because table cells form groups; it's like improperly nesting environments

\begin{A}
\begin{B}
...
\end{A}
\end{B}

which can't work.

Here's a way with etoolbox (I can't recommend using etextools that's buggy and unmaintained).

\documentclass{article}
\usepackage{etoolbox}

%Create a table with a specific amount of columns
\newenvironment{vartab}[1]
  {\begin{tabular}{ |c@{} *{#1}{r|} } \hline}
  {\end{tabular}}

\newcommand{\doentry}[1]{\appto\temp{& #1}}

\newcommand{\entry}[1]{%
  \def\temp{}% initialize to empty
  \forcsvlist{\doentry}{#1}% add entries
  \appto\temp{\\ \hline}% end the row
  \temp % deliver contents
}

\begin{document}

\begin{vartab}{3}
    & 2 & 3 & 4 \\\hline
    \entry{5,6,7}
\end{vartab}

\end{document}

The loop is completely worked out in the first cell, by adding to a temporary command that's expanded at the end.

A different solution uses xparse and expl3; note that the dummy first column is not needed any more.

\documentclass{article} 
\usepackage{xparse}

%Create a table with a specific amount of columns
\newenvironment{vartab}[1]
  {\begin{tabular}{ |*{#1}{r|} } \hline}
  {\end{tabular}}

\ExplSyntaxOn
\NewDocumentCommand{\entry}{m}
 {
  \clist_set:Nn \l_muffel_row_clist { #1 }
  \clist_use:Nn \l_muffel_row_clist { & }
  \\
  \hline
 }
\clist_new:N \l_muffel_row_clist % allocate a clist variable
\ExplSyntaxOff

\begin{document}

\begin{vartab}{3}
  2 & 3 & 4 \\\hline
  \entry{5,6,7}
\end{vartab}

\end{document}

enter image description here

David Carlisle
  • 757,742
egreg
  • 1,121,712