8

I need to construct a table that looks like:

\begin{tabular}{ccc}
a(1,1) & a(1,2) & a(1,3)\\   % <---
a(2,1) & a(2,2) & a(2,3)\\   % <---  I need this
a(3,1) & a(3,2) & a(3,3)\\   % <---
\end{tabular}

for any given number of colums or rows. In fact I only need the part that has arrow next to it, because I would like to be able to put it in different kinds of environments.

I need it to come like some sort of macro, so I can do

\begin{tabular}{ccc}
\generate{a}{3}{3}
\end{tabular}

to get the above table. I've tried:

\newcommand\makerow[3]{
    \foreach \n [count=\ni] in {1,...,#3}{%
        \ifnum\ni=1
            #1(#2,\n)
        \else
            & #1(#2,\n)
        \fi
    }%
}%


\newcommand\makematrix[3]{
    \foreach \m [count=\mi] in {1,...,#2}{%
        \ifnum\mi=#2
            \makerow{#1}{\m}{#3}
        \else
            \makerow{#1}{\m}{#3}\\
        \fi
    }%
}%


\begin{tabular}{ccc}
\makematrix{a}{3}{3}
\end{tabular}

Yet I get this error:

Incomplete \ifnum; All text was ignored after line 81.
Missing \endgoup inserted.
....

What I need

I need a macro to quickly build tabular environments that have a variable number of colums and rows, yet I want to be able to use the tabular as I would do every day:

\begin{tabular}{cc|cc}
\hline
header 1 & header 2 & header 3\\
\hline
foo & bar & baz \\
\makematrix{a}{4}{3}    % <-- makes the rest of the table as described below
\hline    
bar & baz &baz\\
\end{tabular}

etc. So The macro must be just inputted into the tabular environment, and behave as if

a(1,1) & a(1,2) & a(1,3)\\
a(2,1) & a(2,2) & a(2,3)\\
...

were inputted at that spot. Similarly, I would like to be able to define the colums of the tabular environment myself because I'd like to be able tu use > {...} on the columns.

David Carlisle
  • 757,742
romeovs
  • 9,102

1 Answers1

7

This is a possible implementation.

\documentclass{article}

\newtoks\romeotoks
\makeatletter
\newcommand{\makematrix}[4][]{%
  {\global\romeotoks={}%
  \@tempcnta=\z@ \@tempcntb=\z@
  \loop\ifnum\@tempcnta<#3
    \advance\@tempcnta\@ne
    {\loop\ifnum\@tempcntb<#4
       \advance\@tempcntb\@ne
       \edef\next{%
         \ifnum\@tempcntb=\@ne\else&\fi
         \unexpanded{#2}(\number\@tempcnta,\number\@tempcntb)}%
       \global\romeotoks=\expandafter{\the\expandafter\romeotoks\next}%
     \repeat}%
    \@tempcntb=\z@
    \global\romeotoks=\expandafter{\the\romeotoks \\ #1}%
  \repeat}%
  \the\romeotoks}
\makeatother


\begin{document}

\begin{tabular}{cc|c}
\hline
header 1 & header 2 & header 3\\
\hline
foo & bar & baz \\
\makematrix{a}{4}{3}
\hline    
bar & baz &baz\\
\hline
\end{tabular}

\end{document}

The optional argument to \makematrix is something to be put at the end of each row, for example

\makematrix[\hline]{a}{4}{3}

enter image description here

\makematrix has a first optional argument that contains what you want to put after the \\ on each row (for instance, \hline).

EDIT

Here's a LaTeX3 version:

\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \l_romeo_cells_tl
\int_new:N \l_romeo_row_int
\int_new:N \l_romeo_col_int
\NewDocumentCommand { \preparematrix } { O{} m m m }
  {
   \tl_set:Nn \l_romeo_cells_tl { }
   \int_set:Nn \l_romeo_row_int { #3 }
   \int_set:Nn \l_romeo_col_int { #4 }
   \prg_stepwise_inline:nnnn { 1 } { 1 } { \l_romeo_row_int }
     {
      \prg_stepwise_inline:nnnn { 1 } { 1 } { \l_romeo_col_int }
        {
         \int_compare:nF { ####1 = 1 } { \tl_put_right:Nn \l_romeo_cells_tl { & } }
         \tl_put_right:Nn \l_romeo_cells_tl
           { #2 ( ##1 , ####1 ) }
        }
      \tl_put_right:Nn \l_romeo_cells_tl { \\ #1 }
     }
  }
\DeclareExpandableDocumentCommand{ \usematrix } { }
  { \tl_use:N \l_romeo_cells_tl }
\NewDocumentCommand{ \makematrix } { O{} m m m }
  { \preparematrix[#1]{#2}{#3}{#4}\usematrix }

\ExplSyntaxOff

The usage is exactly the same. However I've split the business into two parts, so one can say also

\preparematrix{a}{4}{3}
\begin{tabular}{cc|c}
\hline
header 1 & header 2 & header 3\\
\hline
foo & bar & baz \\
\usematrix
\hline    
bar & baz &baz\\
\hline
\end{tabular}

in case one has to make special adjustments in the first column with \collectcell.

David Carlisle
  • 757,742
egreg
  • 1,121,712
  • Wow nice, is it possible to do this so that the \begin{tabular}{ccc} and \end{tabular} aren't part of \makematrix? This way I can add my own lines, or supply some extra formatting (\hline and whatnot). I'd try editing the code myself but this is way above my head. – romeovs Jan 06 '12 at 15:08
  • 1
    @romeovs The problem is exactly that you can't (easily) do that inside a tabular. Try and show a real example of what you need. – egreg Jan 06 '12 at 15:38
  • I've edited my post to reflect more what I need. – romeovs Jan 06 '12 at 16:29
  • 1
    @romeovs See edited answer – egreg Jan 06 '12 at 16:43
  • this is awe-some, thanks! I'm up voting all I can! – romeovs Jan 06 '12 at 17:05
  • for some reason there is a clash between this and the collcell package. I'm trying to see if I can get some more info about the clash and I'll post a question then. – romeovs Feb 10 '12 at 22:07
  • 1
    @romeovs I've added a LaTeX3 version and tried a simple collcell setting, it worked. But also the old version did. – egreg Feb 10 '12 at 22:51
  • thanks! the problem only arises when the first column is a collcell column, e.g. \newcolumntype{M}{>{\collectcell\textbf}c<{\endcollectcell}}. – romeovs Feb 11 '12 at 08:56
  • 1
    @romeovs With this implementation the entire submatrix is built when LaTeX is already in the first cell of a row, so it cannot work when the first column is given special treatment with \collectcell. – egreg Feb 11 '12 at 09:29
  • I see, I'll try to cook something up myself (this LaTeX3) syntax is a bit more familiar). Any ideas on an approach? Trying to 'make' the matrix before \begin{tabular} and using it with \usematrix doesn't seem to work. Thanks for your help @egreg! – romeovs Feb 11 '12 at 13:36
  • 1
    @romeovs I added the version that can prepare the matrix outside the tabular and then use it inside. – egreg Feb 11 '12 at 13:46
  • ever so helpful. I thank you very much. The last line in \preparematrix (\tl_use:N \l_romeo_cells_tl) is wrong though, it should be removed. – romeovs Feb 11 '12 at 14:17
  • @romeovs It remained from copy-paste; fixed. Thanks. – egreg Feb 11 '12 at 14:33