# How to transpose a table in expl3

I've been very impressed with xparse and expl3, and have written a wonderful document command using \ProcessList that takes a comma separated list and turns it into a (basically) 1 column table.

\stacky{A,B,C,D}
-> \begin{tabular}{rr}
\tiny 1st & A \\
\tiny 2nd & B \\
\tiny 3rd & C \\
\tiny 4th & D
\end{tabular}


Now I've become mad with the power and want to specify more than one column at a time. Something like:

\stacksy{ 5: A,B,C,D ; 6: A,C,D,B ; 3: C,A,B,D }
-> \begin{tabular}{rrrr}
& 5 & 6 & 3 \\ \hline
\tiny 1st & A & A & C \\
\tiny 2nd & B & C & A \\
\tiny 3rd & C & D & B \\
\tiny 4th & D & B & D \\
\end{tabular}


Everything is fine, except that the input is in column-major order, but TeX (or the tabular environment) expects row-major order.

How do I transpose the input list of lists?

-
Not an answer, but it's important to note that xparse is about 'parsing' in the sense 'reading LaTeX2e command syntax' rather than 'parsing arbitrary input'. –  Joseph Wright Sep 5 '12 at 16:13
@JosephWright: Does it sound right that I should be using the sequence splits and maps from expl3 instead of ProcessList from xparse? Scott's solution is working very well, and I'll likely rewrite my single-stack version to use those ideas. –  Jack Schmidt Sep 5 '12 at 18:49
No, as what you are doing is defining an input syntax. I'm simply flagging up that \ProcessList and the like can only take you so far: we've been asked before about extremely complex input, which is really beyond the scope of xparse. Currently, so are nested lists (indeed, I'd have to think hard about a suitable syntax!). –  Joseph Wright Sep 5 '12 at 19:06

Here is a method that will produce a rectangular array of numbers that are given as columns.

• The syntax is stacksys{col 1;col 2;...;col n} where col i is the ith column with entries given as a comma separated list.
• I fiddled with the input a bit to show how column and row headings can be introduced.
• array can be changed to tabular if that is desired.
• \stacksys{,r1,r2;c1,1,2;c2,3,4;c3,5,6} produces:

Code:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\int_new:N \l_ss_num_cols_int
\int_new:N \l_ss_num_rows_int
\bool_new:N \l_has_run_bool

\NewDocumentCommand{\stacksys} {m}
{
\ss_make_table:n {#1}
\int_step_inline:nnnn {1}{1}{\l_ss_num_rows_int}
{
\tl_put_right:cn {l_row_{##1}_tl}{\\}
}
\begin{array}{*{\int_use:N \l_ss_num_cols_int}{c}}
\int_step_inline:nnnn {1}{1}{\l_ss_num_rows_int}
{
\tl_use:c {l_row_{##1}_tl}
}
\end{array}
\bool_gset_false:N \l_has_run_bool
}

\cs_new_protected:Npn \ss_make_table:n #1
{
\seq_set_split:Nnn \l_tmpa_seq {;} {#1}
\int_set:Nn \l_ss_num_cols_int {\seq_count:N \l_tmpa_seq}
\seq_map_function:NN \l_tmpa_seq \ss_process_cols:n
}

\cs_new_protected:Npn \ss_process_cols:n #1
{
\int_zero:N \l_tmpa_int
\seq_set_split:Nnn \l_tmpb_seq {,} {#1}
\int_set:Nn \l_ss_num_rows_int {\seq_count:N \l_tmpb_seq}
\seq_map_inline:Nn \l_tmpb_seq
{
\bool_if:NTF \l_has_run_bool
{
\int_incr:N \l_tmpa_int
\tl_put_right:cn {l_row_{\int_use:N \l_tmpa_int}_tl} {&##1}
}
{
\int_incr:N \l_tmpa_int
\tl_clear_new:c {l_row_{\int_use:N \l_tmpa_int}_tl}
\tl_put_right:cn {l_row_{\int_use:N \l_tmpa_int}_tl} {##1}
}
}
\bool_gset_true:N \l_has_run_bool
}

\ExplSyntaxOff
\begin{document}
$\stacksys{,r1,r2;c1,1,2;c2,3,4;c3,5,6}$
\end{document}

-
Thanks! I'm adjusting it now to my specific situation (and taking care of 100 other tasks). Once I've got it working, I'll accept. Your use of :c is so simple and clear, thanks! [current project is detecting the last row, since somehow I'm getting an extra visible row when using {r|rrr} style tabular headings] –  Jack Schmidt Sep 5 '12 at 18:45
Officially, the colon is supposed to work in \seq_set_split:Nnn right? I agree it doesn't, and I couldn't make it work. The hyphen looks fine, so this is only for curiosity. –  Jack Schmidt Sep 5 '12 at 18:46
I'm not exactly sure, I thought that it "should" work (I couldn't find it excluded in the documentation), but was getting errors so I changed it to the "-". You can switch that to something else if you like. –  Scott H. Sep 5 '12 at 18:49
@ScottH. A few 'LaTeX3 Best Practice' comments. I'd encourage you to pick a single prefix here, both for functions and variables (namespace management is important!): perhaps tabtran? Most of your stuff is not expandable, so \cs_new_protected:Npn would be better than \cs_new:Npn. In 'integer expression' contexts you don't need \int_use:N as TeX automatically does this, so we tend to leave them out. –  Joseph Wright Sep 5 '12 at 19:10
@JosephWright Thanks for the suggestions. I've been trying to remember to add a unique prefix, but forgot this time! For the second I'll have to read up on protected as I don't really understand when it is required. I interpret the third as meaning that if an integer expression is expected, then the \int_use:N is unnecessary because \int_eval is applied anyway? –  Scott H. Sep 5 '12 at 19:21