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.

In a nutshell: I've seen code for creating tables programmatically using tabular. Can it be done using tabularx? If so, how?

I'm a math teacher, and I'd like to create a "problem set" environment in which I can list problems that will be formatted into a table.

Additionally, I'd like the environment to have a parameter that specifies the number of columns the table should have. This bit of modularity is why I'd prefer to use tabularx.

The code below, inspired by other answers I've read here, uses tabular and almost works as I'd like. Including the tabularx package causes the code below to fail with an Illegal pream-token error (update: that's a true statement, although the problem is in array, which is used by tabularx.)

I'd like help with any of the following:

(1) Can I use tabularx instead of tabular? What would I need to change to do so?

(2) If not, I'd like the table to be the same width (\textwidth) no matter how many columns. This code doesn't behave in that way. What am I doing wrong in my current tabular environment?

(3) Unrelated to table creation, but also needs fixing: My scheme for numbering these items is to use a counter and \int_use:N, but the result is that the typeset output always has the last value of the counter. Like I said, I'm new to expl3 programming; to me, this code looks like it like it should work.

(4) Of course, I'm also open to suggestions for better ways to implement this.

Thanks, all!

The code:

\documentclass{article}
\usepackage{xparse}
\usepackage{environ}
\usepackage{lipsum}
\usepackage{tabularx}
\ExplSyntaxOn
\NewEnviron{problemset}[1]{\jermer_pset:V \BODY #1}
\seq_new:N \l_jermer_items_seq
\int_new:N \l_jermer_ncol_int
\int_new:N \l_jermer_ctr_int
\tl_new:N \l_jermer_tblpreamble_tl
\tl_new:N \l_jermer_tblcontent_tl
\cs_new_protected:Npn \jermer_pset:n #1 #2
{
\seq_set_split:Nnn \l_jermer_items_seq { \item } { #1 }
\seq_pop_left:NN \l_jermer_items_seq \l_tmpa_tl % remove empty element
\int_set:Nn \l_jermer_ncol_int { #2 }
\int_zero:N \l_jermer_ctr_int
\tl_clear:N \l_jermer_tblpreamble_tl
\tl_clear:N \l_jermer_tblcontent_tl

\seq_map_inline:Nn \l_jermer_items_seq
{   
    \int_incr:N \l_jermer_ctr_int
    \tl_put_right:Nn \l_jermer_tblcontent_tl { \makebox[1.5em][r]{\__int_value:w \l_jermer_ctr_int}.~ ##1} % ??
    \int_compare:nNnTF {\int_mod:nn {\l_jermer_ctr_int} {\l_jermer_ncol_int}} = {0}
    {\tl_put_right:Nn \l_jermer_tblcontent_tl { \\ }}
    {\tl_put_right:Nn \l_jermer_tblcontent_tl { & }}
}
\int_zero:N \l_jermer_ctr_int
\fp_new:N \l_jermer_wfrac_fp
\fp_set:Nn \l_jermer_wfrac_fp {1 / \l_jermer_ncol_int}
\tl_put_right:Nn \l_jermer_tblpreamble_tl { | }
\int_while_do:nn {\l_jermer_ctr_int < \l_jermer_ncol_int}
{
    \tl_put_right:Nn \l_jermer_tblpreamble_tl { p{ \fp_to_decimal:N \l_jermer_wfrac_fp \textwidth} | } % Even col widths?
%       \tl_put_right:Nn \l_jermer_tblpreamble_tl { X } % Would prefer this!

    \int_incr:N \l_jermer_ctr_int
}
\jermer_draw_table:
}
\cs_generate_variant:Nn \jermer_pset:n { V }
\cs_new:Npn \jermer_draw_table:
{
\begin{center}
% Would prefer to use tabularx here.
\begin{tabular}{\l_jermer_tblpreamble_tl}
\tl_use:N \l_jermer_tblcontent_tl
\end{tabular}
\end{center}
}
\ExplSyntaxOff
\begin{document}
\noindent
\lipsum[1]
\begin{problemset}{3}
    \item Alpha
    \item Beta
    \item Gamma
    \item Delta
    \item Epsilon
    \item Zeta
    \item Eta
    \item Theta
    \item Iota
\end{problemset}
\noindent
\lipsum[1]
\end{document}
share|improve this question
    
Welcome to TeX.SE! –  Mico Mar 10 at 15:47

2 Answers 2

up vote 7 down vote accepted

Here's a solution that also fixes the issue with the item numbers:

\documentclass{article}
\usepackage{xparse}
\usepackage{environ}
\usepackage{lipsum}
\usepackage{tabularx}

\ExplSyntaxOn
\NewEnviron{problemset}[1]{\jermer_pset:Vn \BODY {#1}}

\seq_new:N \l_jermer_items_seq
\int_new:N \l_jermer_ncol_int
\int_new:N \l_jermer_ctr_int
\tl_new:N \l_jermer_tblpreamble_tl
\tl_new:N \l_jermer_tblcontent_tl

\cs_new_protected:Npn \jermer_pset:nn #1 #2
 {
  \seq_set_split:Nnn \l_jermer_items_seq { \item } { #1 }
  \seq_pop_left:NN \l_jermer_items_seq \l_tmpa_tl % remove empty element
  \int_set:Nn \l_jermer_ncol_int { #2 }
  \int_zero:N \l_jermer_ctr_int
  \tl_clear:N \l_jermer_tblpreamble_tl
  \tl_clear:N \l_jermer_tblcontent_tl

  \seq_map_inline:Nn \l_jermer_items_seq
   {   
    \int_incr:N \l_jermer_ctr_int
    \tl_put_right:Nx \l_jermer_tblcontent_tl
     {
      \exp_not:N \makebox[1.5em][r]{\int_to_arabic:n { \l_jermer_ctr_int }}.~\exp_not:n {##1}
     }
    \int_compare:nTF {\int_mod:nn {\l_jermer_ctr_int} {\l_jermer_ncol_int} = 0 }
     {\tl_put_right:Nn \l_jermer_tblcontent_tl { \\ }}
     {\tl_put_right:Nn \l_jermer_tblcontent_tl { & }}
   }
  \tl_put_right:Nn \l_jermer_tblpreamble_tl { | }
  \prg_replicate:nn { #2 } {  \tl_put_right:Nn \l_jermer_tblpreamble_tl { X| } }
  \jermer_draw_table:
 }
\cs_generate_variant:Nn \jermer_pset:nn { V }
\cs_new:Npn \jermer_draw_table:
 {
  \begin{center}
  % Would prefer to use tabularx here.
  \use:x { \exp_not:n {\begin{tabularx}{\textwidth}}{\l_jermer_tblpreamble_tl}}
  \tl_show:N \l_jermer_tblcontent_tl
  \tl_use:N \l_jermer_tblcontent_tl
  \end{tabularx}
  \end{center}
 }
\ExplSyntaxOff

\begin{document}
\noindent
\lipsum[1]
\begin{problemset}{3}
    \item Alpha
    \item Beta
    \item Gamma
    \item Delta
    \item Epsilon
    \item Zeta
    \item Eta
    \item Theta
    \item Iota
\end{problemset}
\noindent
\lipsum[1]
\end{document}

Note that \jermer_pset:nn has two arguments. I removed some parts that were specific to the computation of the column width, since using tabularx is now possible (the trick, as explained by David, is to expand the table preamble).

enter image description here

share|improve this answer
2  
+1 for reading to the end of the question and noticing the additional question about numbering –  David Carlisle Mar 10 at 17:21

Don't blame me! :-)

The issue isn't loading tabularx it is loading array (used by tabularx) and array prevents premature expansion of the tabular preamble (so that macros in @ or >{...}` are expanded when used in the cell, not while building the preamble.

So you need to expand your macro one level when calling the table, either using latex3 utilities, or the old way:

% Would prefer to use tabularx here.
\def\tmp{\begin{tabular}}%
\expandafter\tmp\expandafter{\l_jermer_tblpreamble_tl}
share|improve this answer
    
Should that be \def\tmp{\begin{tabularx}{\textwidth}}\expandafter\tmp\expandafter{\l_jermer_tb‌​lpreamble_tl} since the OP is interested in the tabularx environment? –  Mico Mar 10 at 16:04
    
@Mico yes in the end, but (just) that change is what is required to fix the error reported in the supplied MWE –  David Carlisle Mar 10 at 17:19

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.