4

I have been searching on here for information about comma separated lists, but the only info I have found is how to sort, or iterate over a single list, which isn't quite what I need. If there is a relevant question somewhere I can't find, please feel free to link to it and close this.

What I am after is a way of merging several comma separated lists into a single tabular-type table to generate an answer key to several forms of a multiple choice section of an exam.

So, I would have something like the following:

\begin{document}
\magicFunction{ 
    {A, b, b, a, a, b, b, c}% Test Form A, form is first entry.
    }{
    {B, a, b, c, c, e, a, a}% Test form B
    }{
    {C, c, c, c, a, a, b, c}% Test form C
    }
\end{document}

Which I would want to expand into the following:

\begin{document}
\begin{tabular}{cccc}
\textbf{Problem Number} & \textbf{Form A} & \textbf{Form B} & \textbf{Form C} \\\hline\hline
1  & b & a & c \\
2  & b & b & c\\\hline
3  & a & c & c \\
4  & a & c & a \\\hline
5  & b & e & a \\
6  & b & a & b \\\hline
7  & c & a & c \\
\end{tabular}
\end{document}

The header info isn't hard to just program in, especially since I don't mind having different functions for each number of forms (ie a "2 form" function vs "3 forms" vs "4 forms"; 4 would be the most). The problem I'm having is figuring out how to place the correct answer forms in the correct places. If it were transposed so that I could just inject the entire line I could write the & symbol in the list instead of using a comma-separated list, but for typesetting reasons it's better to have the answers listed vertically since most exams are more like 12-30 multiple choice problems. Moreover I would prefer the magicFunction to be length-independent... meaning that each form will have the same number of answers (so the table will always be full) but any given test might have a different number of answers in it, so that can't be hard coded. I could pass the number of answers in as an argument to the function, but I don't know how to iterate over multiple comma-separated lists simultaneously rather than concatenating the process.

Any help would be hugely appreciated. I don't mind using LaTeX3, which is what I imagine would be the most succinct way to do this, but I'm still clumsy and heavy handed trying to get through parsing all the syntax and naming schemes in LaTeX3, so when I try anything with it myself and get errors I can't figure out what the errors are actually being generated by.

Thanks!

1

2 Answers 2

4
\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\magicFunction}{m}
 {
  \jason_magic:n { #1 }
 }

\int_new:N \l__jason_magic_cols_int
\int_new:N \l__jason_magic_rows_int
\tl_new:N \l__jason_magic_table_tl

\cs_new_protected:Nn \jason_magic:n
 {
  \int_zero:N \l__jason_magic_cols_int
  \int_zero:N \l__jason_magic_rows_int
  \tl_map_inline:nn { #1 }
   {
    \int_incr:N \l__jason_magic_cols_int
    \__jason_magic_makeclist:n { ##1 }
   }
  \__jason_magic_maketable:
  % print the table
  \begin{tabular}{ c *{\l__jason_magic_cols_int}{c} }
  \l__jason_magic_table_tl
  \end{tabular}
 }

% syntactic sugar for avoiding long strings
\cs_new:Nn \__jason_magic_clist:n
 {
  l__jason_magic_ \int_eval:n { #1 } _clist
 }

% store the parts in clists and get the number of rows
\cs_new_protected:Nn \__jason_magic_makeclist:n
 {
  \clist_clear_new:c { \__jason_magic_clist:n { \l__jason_magic_cols_int } }
  \clist_set:cn { \__jason_magic_clist:n { \l__jason_magic_cols_int } } { #1 }
  \int_set:Nn \l__jason_magic_rows_int
   {
    \int_max:nn
     { \l__jason_magic_rows_int }
     { \clist_count:c { \__jason_magic_clist:n { \l__jason_magic_cols_int } } }
   }
 }

\cs_new_protected:Nn \__jason_magic_maketable:
 {
  % make the first row
  \tl_set:Nn \l__jason_magic_table_tl { Problem~number }
  \int_step_inline:nn { \l__jason_magic_cols_int }
   {
    \tl_put_right:Nx \l__jason_magic_table_tl
     {
      & Form~\int_to_Alph:n { ##1 }
     }
   }
  \tl_put_right:Nn \l__jason_magic_table_tl { \\ \hline }
  % make the following rows
  \int_step_inline:nn { \l__jason_magic_rows_int }
   {
    \tl_put_right:Nx \l__jason_magic_table_tl { ##1 }
    \int_step_inline:nn { \l__jason_magic_cols_int }
     {
      \tl_put_right:Nx \l__jason_magic_table_tl
       {
        & \clist_item:cn { \__jason_magic_clist:n { ####1 } } { ##1 }
       }
     }
    \tl_put_right:Nn \l__jason_magic_table_tl { \\ }
    \int_if_odd:nF { ##1 } { \tl_put_right:Nn \l__jason_magic_table_tl { \hline } }
   }
 }

\ExplSyntaxOff

\begin{document}

\magicFunction{ 
    {b, b, a, a, b, b, c}% Test Form A, form is first entry.
    {a, b, c, c, e, a, a}% Test form B
    {c, c, c, a, a, b, c}% Test form C
}

\end{document}

enter image description here

The idea is to allocate a clist for every column. Then the table is built by extracting the relevant item from each clist, by stepping the row index.

6
  • This looks promising, but just copy-pasting your code gives the following error in my log: (comments not having linebreaks may make this bad...) ! Undefined control sequence. __jason_magic_maketable: ...}\int_step_inline:nn {\l__jason_magic_cols_int ... l.86 }
    – Jason
    Apr 4, 2019 at 18:07
  • I discovered I am using texlive 2015 on this machine, which is an older version than I typically use. I am in the process of updating texlive, and suspect that may be causing some (if not all) of the issue. I'll comment again if I still get an error afterward; or if you reply with a suggested fix.
    – Jason
    Apr 4, 2019 at 18:46
  • @Jason TeX Live 2015 is very outdated.
    – egreg
    Apr 4, 2019 at 20:05
  • Yea, I was ... surprised to discover I was running that (on a new linux VM right now) still downloading and upgrading the texlive install, so hopefully this will fix numerous small annoyances I've been dealing with. I guess this question has helped me more than I expected lol.
    – Jason
    Apr 4, 2019 at 20:13
  • Finally finished updating everything (bit of an adventure as it turns out) and this code works fine now. Thanks for the help!
    – Jason
    Apr 4, 2019 at 21:37
0

Not a complete answer but something for you to think about. The memoir class provides for what it calls automated tabulars where the input essentially consists of a comma-seperated list of entries to be tabulated in either a row-ordered (\autorows) fashion or column-ordered (\autocols) fashion.

For instance:

\documentclass{memoir}
\begin{document}
\autorows{c}{3}{l}{one, two, three, four, five, six, seven}
\end{document}

will produce a tabular looking like (apologies, I'm a GOM and haven't yet managed to upload a graphic)

one   two  three
four  five six
seven

See section 11.8.2 Automatic tabulars in the manual for more information (> texdoc memoir).

1
  • Well this is fascinating, I had no idea such a thing existed... I'm going to have to look into this. Thanks!
    – Jason
    Apr 4, 2019 at 17:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .