Build table elements using a macro

1. Small example

Consider the following two tables:

\documentclass{article}
\usepackage{multirow}
\usepackage{hyperref}
\begin{document}
\begin{tabular}{c | c c | c}
\multirow{4}{*}{First}  & First(     & \hypertarget{firststuff.<third argument>}{}Some      & \multirow{4}{*}{\hyperlink{secondstuff.<third argument>}{$\rightarrow$}}    \tabularnewline
& Example      & more      &                       \tabularnewline
& of a & elements      &                       \tabularnewline
& table        & in the third      & \tabularnewline
\hline
\multirow{4}{*}{First}  & First(     & \hypertarget{firststuff.<third argument>}{}Some      & \multirow{4}{*}{\hyperlink{secondstuff.<third argument>}{$\rightarrow$}}    \tabularnewline
& Example      & more      &                       \tabularnewline
& of a & elements      &                       \tabularnewline
& table        & in the third      &
\end{tabular}
\vspace{\parindent}

The above table has two elements and four rows. The one down below has one element and five rows.

\vspace{\parindent}
\begin{tabular}{c | c c | c}
\multirow{5}{*}{Second}                    & Second(     & \hypertarget{firststuff.<third argument>}{}Some & \multirow{5}{*}{\hyperlink{stuff.<third argument>}{$\rightarrow$}}     &                       \tabularnewline
& example      & more      &                       \tabularnewline
& of this & elements      &             \tabularnewline
& table        & in the third      &                       \tabularnewline
& \textbf{Woah} & \textbf{an}   &
\end{tabular}
\end{document}


2. Terms & wording

To remove ambiguity from the request, some explanation on the used terms:

• \mymacro{#1} - has one argument.
• \mymacro{one,two,three} - This macro has one argument and three parts of the argument (to be named "parts" in the request).
• One table element consists of one portion created by the macro.

See:

\documentclass{article}
\usepackage{multirow}
\usepackage{hyperref}
\begin{document}
\begin{tabular}{c | c c | c}
\multirow{4}{*}{First}  & First(     & \hypertarget{firststuff.<third argument>}{}Some      & \multirow{4}{*}{\hyperlink{stuff.<third argument>}{$\rightarrow$}}    \tabularnewline
& Example      & more      &                       \tabularnewline
& of a & elements      &                       \tabularnewline
& table        & in the third      & \tabularnewline
\hline
\multirow{4}{*}{First}  & First(     & Some      & \multirow{4}{*}{\hyperlink{stuff.<third argument>}{$\rightarrow$}}    \tabularnewline
& Example      & more      &                       \tabularnewline
& of a & elements      &                       \tabularnewline
& table        & in the third      &
\end{tabular}
\end{document}

• The above table has two elements and four rows. The elements are essentially the product of the iterative process each time the macro is used. This can be easily recognized by the times \multirow{4}{*}{...} is used in this case.

3. Intended effect

I wish to automate the process of making these table elements, by using a macro which will look a little like this: \mymacro{#1}{#2}{#3} and will be very similar to say, \newcommand{\mymacro}[3]{#1&#2&#3}. This macro is supposed to make the entire "element" (consisting of multiple rows). The arguments of this macro may appear non-intuitive.

• Arguments #1 and #2 should hold multiple parts, delimited by commas (same as Macro evaluating number of arguments without limitation) EXAMPLE: \mymacro{I,love,cake,and,pie}{You,hate,cake,and,pie}{...}. The amount of "parts" in either of these two elements will determine the number of rows in the second and third column (as outlined in the example).
• The first column in the table will contain the first argument (between { and ,) of #1. (See EXTRA below)
• #2 pretty much behaves like #1, so I can type the same number of parts as I have used in #1.
• The fourth column has the same alignment as the first. To achieve that, a \multirow{n}{*}{...} there, for n amount of rows, should suffice.
• The table element is intended to hold verbatim commands like \mintinline{Python}{#1} or other fancrVrb related commands like \lstinline.
• #3 will hold an argument for hyperlinks and hypertargets, as also included in the examples above.
• The last column (number 4) will be static and show a $\rightarrow$ or something.

To clarify, here's a picture:

4. Page breaking

One element should appear, as a whole, on one page. Very much preferred is to not break a page mid-element, if longtable is used. This can be easily circumvented by the usage of \\* of course, as outlined below:

\documentclass{article}
\usepackage{geometry}
\usepackage{longtable}
\usepackage{array}
\begin{document}
{\renewcommand*\arraystretch{3}
\begin{longtable}{c c c c c}
some & serious & stuff\\
\hline
& stuff \\
\\
\\
\\
\\
\\
\\
\\
\\
\\
\\
& is \\*
& one \\*
\textbf{\Large This} & of \\*
& those \\*
& elements \\
\end{longtable}
}
\end{document}


Removing the asterisks will make the page break in the middle of the table "element".

5. Usage of the macro

The macro is to be used multiple times as "stand-alone" element in the table. EXAMPLE A table should be able to hold mymacro multiple times as such:

\documentclass{article}
\usepackage{multirow}
\begin{document}
\begin{tabular}{c c c c c}
\mymacro{dummy,elements,in the second, column}{some,more,elements,in the third}{hyperlinkinfourthcolumn}
\mymacro{dummy,elements,in the second, column}{some,more,elements,in the third}{hyperlinkinfourthcolumn}
\end{document}


It's important that the macro only creates elements to be used inside a table (so as a substitute for the actual Some text & more text & text text text \tabularnewline for each row of table cells, but instead this macro will do several rows and (parts of) columns.). I wish to create one big table which holds these elements.

6. First part of #1 to be reused in first column of the table (optional)

• In my case the first argument of #1 will look a little like <stuff>(.
• (i) in the single cell in the first column of the table (Where "first example" and "second example" stands in the table compiled from the example above), I wish to display <stuff>.
• (ii) I want arguments 1 through n (so including the one I already printed in the first column) printed in the second column. In this column I just want to see <stuff>(, including a brace.

So far what I have is this:

\documentclass{article}
\usepackage{xparse}
\usepackage{longtable}
\usepackage{multirow}
\usepackage{hyperref}

\ExplSyntaxOn
\NewDocumentCommand{\mymacro}{ m m }
{
\ioiooiioio_setargs:nn { #1 } { #2 }
\ioiooiioio_print:
}

\seq_new:N \l__ioiooiioio_first_col_seq
\seq_new:N \l__ioiooiioio_second_col_seq
\tl_new:N \l__ioiooiioio_table_body_tl
\int_new:N \l__ioiooiioio_step_int
\int_new:N \l__ioiooiioio_args_int

\cs_new_protected:Npn \ioiooiioio_setargs:nn #1 #2
{
\seq_set_split:Nnn \l__ioiooiioio_first_col_seq { , } { #1 }
\seq_set_split:Nnn \l__ioiooiioio_second_col_seq { , } { #2 }
\tl_clear:N \l__ioiooiioio_table_body_tl
\int_zero:N \l__ioiooiioio_step_int
\int_set:Nn \l__ioiooiioio_args_int { \seq_count:N \l__ioiooiioio_first_col_seq }
\l__ioiooiioio_first_col_seq
\l__ioiooiioio_second_col_seq
\__ioiooiioio_fill_body:nn
}

\cs_new_protected:Npn \__ioiooiioio_fill_body:nn #1 #2
{
\int_incr:N \l__ioiooiioio_step_int
\tl_put_right:Nn \l__ioiooiioio_table_body_tl { & #1 & #2 & }
\int_compare:nT { \l__ioiooiioio_step_int = 1}
{
\tl_put_right:Nn \l__ioiooiioio_table_body_tl
{
\multirow{ \l__ioiooiioio_args_int }{*}{
\hyperlink { #1 } { $\rightarrow$ }
}
}
}
\int_compare:nTF { \l__ioiooiioio_step_int = \l__ioiooiioio_args_int}
{
\tl_put_right:Nn \l__ioiooiioio_table_body_tl
{ \\ }
}
{
\tl_put_right:Nn \l__ioiooiioio_table_body_tl
{ \\* }
}
}

\cs_new_protected:Npn \ioiooiioio_print:
{
\multirow{ \l__ioiooiioio_args_int }{*}{ \seq_item:Nn \l__ioiooiioio_first_col_seq { 1 } } \l__ioiooiioio_table_body_tl
}
\ExplSyntaxOff

\begin{document}
\begin{longtable}{cccc}
\mymacro{this is a test,this,is a,test}{now its,not a,test,anymore}
\end{longtable}
\end{document}


I ran into two problems with this though:

First thing: So I've looked at the interface3 documentation for \seq_mapthread_function and I strongly suspect it supports two arguments and two arguments only. I wish to use a third argument which will only print the hyperlink for the first row. (@egreg's answer just glues it to the right, I wish to embed it in the table, see example.) Do I have to use another sequence here? The third argument #3 will only be printed once and will therefore be static, currently the argument shows #1 due to lack of a better alternative. I also can't picture \seq_mapthread_function to work as intended with a third argument. The intended effect is to have a hyperlink with an arbitrary argument inside it. \hyperlink{<whatever I can think of>}{$\rightarrow$}.

Second thing: Usage of \multirow about the hyperlink spawns an overfull vbox. I cannot explain this error and the only question related to this vbox and \multirow, was an "actual" case of an overfull vbox, which was caused by an element too large: Removing an "Overfull \vbox" message caused by a nested table. I had trouble finding the relation between the solution in that thread and my case. How can I deal with this error? The intended effect is to make this $\rightarrow$ (and hyperlink of course) align with the first column of the table, which would be determined by the total number of arguments by the usage of \multirow{ \l__ioiooiioio_args_int }{*}{...}.

• You simply can't have verbatim material in the argument of other commands. What kind of verbatim do you have in mind? May 29, 2014 at 9:24
• @egreg \newcommand{\code}[1]{\mintinline{r}{#1}} is what I used in the body text. Would be nice if that also worked inside the table. May 29, 2014 at 9:25
• Your question has undergone 20 revisions, all by you. And the most problematic feature request has appeared just now, without any example. The presentation is confused and unmotivated. I'm not going to spend more time on it, sorry. May 29, 2014 at 9:29
• @egreg Shame. Your answer was actually closest so far... May 29, 2014 at 9:50
• big shots seem intent on abandoning you, but I will give a try despite the fact that please please make your mwe fit on small screens. All those whitespaces and long long lines are just not compatible with small budget practitioners.
– user4686
May 29, 2014 at 15:25

It's apparent that the first and last items are not columns of a table, but just items to be set next to the real table.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\mymacro}{ m m m }
{
\ioiooiioio_setargs:nn { #1 } { #2 }
\mbox { \ioiooiioio_print:n { #3 } }
}

\seq_new:N \l__ioiooiioio_first_col_seq
\seq_new:N \l__ioiooiioio_second_col_seq
\tl_new:N \l__ioiooiioio_table_body_tl

\cs_new_protected:Npn \ioiooiioio_setargs:nn #1 #2
{
\seq_set_split:Nnn \l__ioiooiioio_first_col_seq { , } { #1 }
\seq_set_split:Nnn \l__ioiooiioio_second_col_seq { , } { #2 }
\tl_clear:N \l__ioiooiioio_table_body_tl
\l__ioiooiioio_first_col_seq
\l__ioiooiioio_second_col_seq
\__ioiooiioio_fill_body:nn
}

\cs_new_protected:Npn \__ioiooiioio_fill_body:nn #1 #2
{
\tl_put_right:Nn \l__ioiooiioio_table_body_tl { #1 & #2 \\ }
}

\cs_new_protected:Npn \ioiooiioio_print:n #1
{
\seq_item:Nn \l__ioiooiioio_first_col_seq { 1 }
\hspace{\tabcolsep}
\begin{tabular}{|cc|}
\l__ioiooiioio_table_body_tl
\end{tabular}
\hspace{\tabcolsep}
#1
}

\ExplSyntaxOff

\begin{document}

\mymacro{dummy,elements,in the second, column}{some,more,elements,in the third}{fourth column}

\end{document}


Despite all the edits it still isn't very clear what you want, also I couldn't see why the first column should be part of the comma list so I made it a separate argument. perhaps something like:

\documentclass{article}

\def\mymacro#1#2#3#4{%
\par
#1%
\begin{tabular}{|c|c|}
\zz#2,\zzend\yy#3,\relax\qq
\end{tabular}%
#4%
\par}

\def\zzend#1\qq{}

\def\zz#1,#2\yy#3,#4\qq{#1&#3\\
\ifx\zzend#2\expandafter\zzend\fi
\zz#2\yy#4\qq
}

\begin{document}

\mymacro{first}{dummy,elements,in the second, column}{some,more,elements,in the third}{fourth column}
\mymacro{first}{dummy,elements,in the second, column}{some,more,elements,in the third}{fourth column}

\end{document}


I wasn't sure what to do if #1 contained more elements than #2 or vice versa. Here, I just truncate if this arises. Moreover the added ('s in the top cell of the second column seem weird.

This final update is with a better method: no package, only use of a counter and taking advantage of the possibility of using \multirow with a negative first argument.

\documentclass[a4paper,12pt]{article}
\usepackage{multirow}
\usepackage{hyperref}

\makeatletter

\newcounter{rowcnt}

\newcommand\mymacro [3]{%
\mymacro@next@a #1,\@nnil #2,\@nnil\@nil {#3}%
}

\def\mymacro@next@a #1,#2\@nnil #3,#4\@nil #5{%
\setcounter{rowcnt}{-\tw@}
& #1 ( & #3 & \\
\mymacro@next@b #2\@nnil #4\@nil {#1}{#5}}

\def\mymacro@next@b #1,#2\@nnil #3,#4\@nnil\@nil #5#6{%
\ifx\@nnil#2\@nnil\expandafter\@thirdofthree
\else\ifx\@nnil#4\@nnil
\expandafter\expandafter\expandafter\@thirdofthree
\fi\fi
\@firstoftwo {\addtocounter{rowcnt}{\m@ne}& #1 & #3 & \\
\mymacro@next@b #2\@nnil #4\@nnil\@nil {#5}{#6}}
{\multirow {\value{rowcnt}}{*}{#5}& #1 & #3 &
\multirow {\value{rowcnt}}{*}{\hyperlink{stuff.#6}{$\rightarrow$}}\\}%
}

\makeatother

\begin{document}

{\centering\begin{tabular}{c|cc|c}
\hline\hline
\multirow{4}{1cm}{First\\(literal input)} & First (
& Some
& \multirow{4}{*}{
\hyperlink{stuff.}{$\rightarrow$}}
\tabularnewline
& Example & more &   \tabularnewline
& of a & elements &  \tabularnewline
& table & in the third & \\
\hline
\mymacro {First,Example,of a,table}{Some,more,elements,in the third}{A}
\hline
\mymacro {Second,Example,of a,table,with,more,elements}
{Some,elements,in the,third,column}{B}
\hline
\mymacro {Third,Example,with,less,elements}
{Too,many,elements,in,the,third,column}{C}
\hline
\mymacro {Fourth,Example,with,many,many,many,many,elements}
{Many,many,elements,in,the,third,column,isn't it?}{D}
\hline\hline
\end{tabular}\par }

\hypertarget{stuff.}{Top target}

\hypertarget{stuff.A}{Second target}

\hypertarget{stuff.B}{Third target}

\hypertarget{stuff.C}{Fourth target}

\hypertarget{stuff.D}{Fifth target}

\end{document}


Earlier proposal.

\documentclass[a4paper,12pt]{article}
\usepackage{multirow}
\usepackage{hyperref}
\usepackage{xinttools}

\makeatletter

\newcommand\mymacro [3]{%
\mymacro@next@a #1,\@nnil #2,\@nnil\mymacro@next@e
{\multirow {\xintNthElt{0}{\xintCSVtoListNonStrippedNoExpand{#1}}}{*}}{#3}%
%
% OR IN CASE #1 AND #2 MAY HAVE DISTINCT NUMBERS OF ITEMS
% do \usepackage{xint} and use: (not efficient, but did not know if really needed; if really needed then was can aslo do without xint)
%    {\multirow {\xintiMin{\xintNthElt{0}{\xintCSVtoListNonStrippedNoExpand{#1}}}
%                         {\xintNthElt{0}{\xintCSVtoListNonStrippedNoExpand{#2}}}}{*}}{#3}%
}
\def\mymacro@next@a #1,#2\@nnil #3,#4\mymacro@next@e #5#6{%
#5{#1}& #1 ( & #3 & #5{\hyperlink{stuff.#6}{$\rightarrow$}}\\
\mymacro@next@b #2\@nnil #4\mymacro@next@e }

\def\mymacro@next@b #1,#2\@nnil #3,#4\@nnil\mymacro@next@e {%
& #1 & #3 & \\
\ifx\@nnil#2\@nnil\expandafter\mymacro@next@e
\else\ifx\@nnil#4\@nnil
\expandafter\expandafter\expandafter\mymacro@next@e
\fi\fi
\mymacro@next@b #2\@nnil #4\@nnil\mymacro@next@e }

\def\mymacro@next@e #1\mymacro@next@e {}

\makeatother

\begin{document}\pagestyle{empty}

{\centering
\begin{tabular}{c|cc|c}
\hline\hline
\multirow{4}{1cm}{First\\(literal input)} & First(
& Some
& \multirow{4}{*}{
\hyperlink{stuff.}{$\rightarrow$}}
\tabularnewline
& Example & more &   \tabularnewline
& of a & elements &  \tabularnewline
& table & in the third & \\
\hline
\mymacro {First,Example,of a,table}{Some,more,elements,in the third}{A}
\hline
\mymacro {Second,Example,of a,table,with,more,elements}
{Some,elements,in the,third,column}{B}
\hline
\mymacro {Third,Example,with,less,elements}
{Too,many,elements,in,the,third,column}{C}
\hline\hline
\end{tabular}\par }

\hypertarget{stuff.}{Top target}

\hypertarget{stuff.A}{Second target}

\hypertarget{stuff.B}{Third target}

\hypertarget{stuff.C}{Fourth target}

\end{document}