Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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?

share|improve this question
    
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
add comment

1 Answer

up vote 8 down vote accepted

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:

enter image description here

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}
share|improve this answer
    
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
show 5 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.