How to apply a macro to each row of a table

This is similar to the question about cells, but with whole rows, and hopefully will help me to implement an answer to this question.

Given a macro \RowMacro, how can I define the mytable environment such that I an write in my document

\begin{mytable}
a & b & c \\
d & e & f \\
g \\
h & i & j
\end{mytable}


and get the same result as if I had written

\RowMacro{a}{b}{c}
\RowMacro{d}{e}{f}
\RowMacro{g}{}{}
\RowMacro{h}{i}{j}


The maximum number of columns may have to be specified upfront.

Package environ to capture the contents of an environment. LaTeX3 code (package expl3) to split it into lines, cells, and more general programming tools. Rather than making an environment with 4 parameters as I did, you can hard-code some of them in the definition if it is more practical.

\documentclass{article}
\usepackage{environ}
\usepackage{expl3}
\ExplSyntaxOn
\seq_new:N \l_jb_lines_seq
\seq_new:N \l_jb_tmp_seq
\tl_new:N \l_jb_result_tl
\int_new:N \l_jb_cols_int
\int_new:N \l_jb_cell_int
\tl_new:N \l_jb_one_line_tl
\NewEnviron{mytable}[4][]
{
\seq_set_split:NnV \l_jb_lines_seq { \\ } \BODY
%
% If the user gives no indication of number of cells, find the max
% number by reading all rows.  Otherwise, use the user-given value,
% all extras will be thrown out silently.
%
\tl_if_empty:nTF {#1}
{ \jb_get_max_cells:NN \l_jb_lines_seq \l_jb_cols_int }
{ \int_set:Nn \l_jb_cols_int {#1} }
%
% Build the result into a token list, initially the begin-code |#3|.
% For each line |##1|, add a call to the command |#2| with exactly
% |\l_jb_cols_int| arguments.  Then append the end-code |#4|.
% Finally, use the token list.
%
\tl_set:Nn \l_jb_result_tl {#3}
\seq_map_inline:Nn \l_jb_lines_seq
{ \jb_append_one_line:NnNn \l_jb_result_tl {#2} \l_jb_cols_int {##1} }
\tl_put_right:Nn \l_jb_result_tl {#4}
\tl_use:N \l_jb_result_tl
}
\cs_new_protected:Npn \jb_get_max_cells:NN #1#2
{
% Find the max number of cells over all lines.
% Not terribly efficient way of counting |&|: split at each |&|
% and store in a tmp sequence, then count its items.
%
\int_zero:N #2
\seq_map_inline:Nn #1
{
\seq_set_split:Nnn \l_jb_tmp_seq { & } {##1}
\int_set:Nn #2
{ \int_max:nn #2 { \seq_count:N \l_jb_tmp_seq } }
}
}
\cs_new_protected:Npn \jb_append_one_line:NnNn #1#2#3#4
{
\tl_set:Nn \l_jb_one_line_tl {#2}
\seq_set_split:Nnn \l_jb_tmp_seq { & } {#4}
\int_set:Nn \l_jb_cell_int { \seq_count:N \l_jb_tmp_seq }
\int_compare:nNnTF \l_jb_cell_int > {#3}
{
\int_zero:N \l_jb_cell_int
\seq_map_inline:Nn \l_jb_tmp_seq
{
\int_compare:nNnF \l_jb_cell_int < {#3} { \seq_map_break: }
\int_incr:N \l_jb_cell_int
\tl_put_right:Nn \l_jb_one_line_tl { {##1} }
}
}
{
\seq_map_inline:Nn \l_jb_tmp_seq
{ \tl_put_right:Nn \l_jb_one_line_tl { {##1} } }
\tl_put_right:Nx \l_jb_one_line_tl
{ \prg_replicate:nn { #3 - \l_jb_cell_int } { { } } }
}
\tl_put_right:NV #1 \l_jb_one_line_tl
}
\ExplSyntaxOff
\begin{document}
\newcommand{\RowMacro}[5]{[1: #1] & [2: #2] & [3 and 4: #3, #4] & [5: #5]\\}
\begin{mytable}[5]{\RowMacro}{\begin{tabular}{cccc}}{\end{tabular}}
a & b & c \\
d & e & f & g & h & extra\notused \\
ijk & l
\end{mytable}
\end{document}

• Whoa, scary code, but might be just what I was looking for. In particular it seems to be able do do other things that I was planning on (such as measuring the cells to decide upon a particular layout). – Joachim Breitner May 22 '13 at 14:01
• Is expl3 something that is commonly around? Or would I have to worry using it in a submission to a CS journal? – Joachim Breitner May 22 '13 at 14:03
• @JoachimBreitner My worry is that their versions would be too old. As far as I can tell, this code requires an expl3 more recent than 2012-07-02, relatively more recent than what journals would have. – Bruno Le Floch May 22 '13 at 14:28

A simple solution, if you know the number of columns:

\def\RowMacroIII{{#1}&{#2}&{#3}\\}


Usage

\RowMacro{a}{b}{c}


and

\def\RowMacroIV{{#1}&{#2}&{#3}&{#4}\\}


Usage

\RowMacro{a}{b}{c}{d}

• I think you got my question wrong: I want to write \begin{mytable}... &.. \end{mytable}, and define the behavior by defining \RowMacro. Let me clarify that. – Joachim Breitner May 22 '13 at 12:25
• @JoachimBreitner So, if you have table with three colums, you define \RowMacro as \RowMacroIII is defined and so on, up to 9 parameters. Am I missing something? – Przemysław Scherwentke May 22 '13 at 13:34
• Yes, I think so. How do I write the code for mytable that parses the sequnce of cells, & and \ and passes them to \RowMacro? – Joachim Breitner May 22 '13 at 13:52