15

Is there an easy way to break long narrow tables into two (or possibly more) columns (i.e. without manually rearranging the columns)?

In the following example you can see that there is a lot of wasted space, because there is a long table with a lot of white space next to it (and \twocolumn didn't work as I would have liked it to...):

\documentclass{article}

\begin{document}

\begin{table}
  \centering
  \twocolumn
  \begin{tabular}{cc}
    \hline
    thing & mapsto \\
    \hline
    foo 0 & bar 2 \\
    foo 1 & bar 3 \\
    foo 2 & bar 4 \\
    foo 3 & bar 5 \\
    foo 4 & bar 6 \\
    foo 5 & bar 7 \\
    foo 6 & bar 8 \\
    foo 7 & bar 9 \\
    foo 8 & bar 10 \\
    foo 9 & bar 11 \\
    foo 10 & bar 12 \\
    foo 11 & bar 13 \\
    foo 12 & bar 14 \\
    foo 13 & bar 15 \\
    foo 14 & bar 16 \\
    foo 15 & bar 17 \\
    foo 16 & bar 18 \\
    foo 17 & bar 19 \\
    foo 18 & bar 20 \\
    foo 19 & bar 21 \\
    \hline
  \end{tabular}
  \caption{What is this?}
  \onecolumn
\end{table}

Pellentesque sed posuere magna. Ut pellentesque dictum posuere. Mauris at justo ipsum. Maecenas sit amet neque erat, nec euismod nisi. Nullam posuere convallis massa vel luctus. Etiam vestibulum semper lectus, sed ultrices leo aliquet sit amet. Vestibulum in lorem vitae magna scelerisque porttitor ut volutpat dui. Nulla risus felis, molestie et tincidunt sit amet, ullamcorper vestibulum erat. Pellentesque bibendum porttitor velit, at tempor erat sollicitudin at. Sed nec nunc lacus. Sed sollicitudin sollicitudin risus sit amet mollis. Nam posuere tincidunt lacus, ut placerat arcu pharetra at. Proin tempus, orci sed consequat consequat, nulla augue tempus augue, vel fermentum mi augue eget odio.

\end{document}

So in the end the result should look like what I would get by manually changing the above table to:

  \begin{tabular}{ccp{1em}cc}
    \hline
    thing & mapsto && thing & mapsto \\
    \hline
    foo 0 & bar 2 && foo 10 & bar 12 \\
    foo 1 & bar 3 && foo 11 & bar 13 \\
    ...

I am using booktabs so it would be nice if a potential solution were compatible to this package. (A related question is Two Column Layout for Tables where I got the idea with \twocolumn from.)

6
  • Have a look at tex.stackexchange.com/questions/13895/….
    – lockstep
    Commented Aug 31, 2011 at 14:47
  • Don't think there is an easy way. But, perhaps one could use the collcell package. To simplify the task it might be helpful to specify how many times the table is to be broken, and which rows are to be repeated at the top. Commented Sep 11, 2011 at 5:46
  • I think no more than one or two times. And only the header should be repeated. (cf. example) Commented Sep 11, 2011 at 9:45
  • Bruno's answer looks good to me. Anything missing from it that you don't accept it?
    – Christian
    Commented May 28, 2012 at 21:47
  • Have you tried it? It doesn't work for me. Commented May 29, 2012 at 18:48

2 Answers 2

7

pgfplotstable can do this sort of arrangement.

The purpose of pgfplotstable is to load (large) data files and to process them. Its typical use case is to postprocess and pretty-print numerical tables.

However, it is also capable of breaking huge columns into two (or three or whatever); and it can also process non-numerical data. It accepts CSV files or files delimited with & and \\. However, it is NOT tabular: it expects "raw data" and generates a suitable tabular.

While it can easily handle the task to dynamically balance multiple columns, the cost for you is to learn how to reinsert your "old" formatting instructions like \hlines or \multicolumns. You will also have to learn how to assign column display names, how to add any vertical lines or so. It can do all these things, its just different because the tool has a different use-case (it assumes that there is no tabular, only a data file).

Here is your example. I took the freedom to add sample answers to some of the questions raised in the last paragraph:

enter image description here

\documentclass{standalone}

\usepackage{pgfplotstable}
\usepackage{booktabs}

\begin{document}

\pgfplotstabletypeset[
    every head row/.style={before row=\toprule,after row=\midrule},
    every last row/.style={after row=\bottomrule},
    col sep=ampersand,
    row sep=\\,
    %
    columns={thing,mapsto,thing,mapsto},
    display columns/0/.style={
        % first part of 2 of `thing':
        select equal part entry of={0}{2},
        string type,
            % column display name:
        column name={thing (1/2)},
        column type={r}, % ... and type
    },
    display columns/1/.style={
        % first part of 2 of `mapsto':
        select equal part entry of={0}{2},
        string type,
        column name={thing (2/2)},
        column type={l|},
    },
    display columns/2/.style={select equal part entry of={1}{2},string type},% second part of 2 of `thing'
    display columns/3/.style={select equal part entry of={1}{2},string type},% second part of 2 of `maps'
]{
    thing & mapsto \\
    foo 0 & bar 2 \\
    foo 1 & bar 3 \\
    foo 2 & bar 4 \\
    foo 3 & bar 5 \\
    foo 4 & bar 6 \\
    foo 5 & bar 7 \\
    foo 6 & bar 8 \\
    foo 7 & bar 9 \\
    foo 8 & bar 10 \\
    foo 9 & bar 11 \\
    foo 10 & bar 12 \\
    foo 11 & bar 13 \\
    foo 12 & bar 14 \\
    foo 13 & bar 15 \\
    foo 14 & bar 16 \\
    foo 15 & bar 17 \\
    foo 16 & bar 18 \\
    foo 17 & bar 19 \\
    foo 18 & bar 20 \\
    foo 19 & bar 21 \\
}
\end{document}

See http://pgfplots.sourceforge.net/pgfplotstable.pdf

5

One method is to collect the body of the tabular using Will Robertson's environ package, then reorganize the rows using LaTeX3 code.

First separate the rows and store them into a "sequence variable" (in other languages that would be called a list) using \seq_set_split:Nnn. Since the table ends with \\, the resulting sequence ends with an empty item. The first item of the sequence (the first row of the table) is the header, which we will have to repeat. We can "pop" that first row from the sequence and store it in \l_DT_header_tl for later reuse. Then pop the next L/2 items from the sequence, and store them into another sequence, where L is the length of the initial sequence (number of rows in your table). We now have two sequences, contents_A holds the first half of the table, and contents holds the second half.

Here comes some magic function (which only exists for two sequences, otherwise we'd have more work), \seq_mapthread_function:NNN, which allows us to take items from both sequences in parallell, and hence typeset them side-by-side: \DT_one_row:nn takes one item from each sequence and expands to one row of the result, #1&&#2\\.

\documentclass{article}
\usepackage{booktabs}
\usepackage{environ}
\usepackage{expl3}
\ExplSyntaxOn
\seq_new:N \l_DT_contents_seq
\seq_new:N \l_DT_contents_A_seq
\tl_new:N \l_DT_header_tl
\cs_generate_variant:Nn \seq_set_split:Nnn { NnV }
\NewEnviron{dbltbl}[2]
  {
    % Separate the rows.
    \seq_set_split:NnV \l_DT_contents_seq { \\ } \BODY

    % Extract the header.
    \seq_pop_left:NN \l_DT_contents_seq \l_DT_header_tl

    % Split the table between "contents_A" and "contents".
    \seq_clear:N \l_DT_contents_A_seq
    \prg_replicate:nn
      { \int_div_truncate:nn { \seq_length:N \l_DT_contents_seq } {2} }
      {
        \seq_pop:NN \l_DT_contents_seq \l_tmpa_tl
        \seq_put_right:NV \l_DT_contents_A_seq \l_tmpa_tl
      }

    % Typeset.
    \begin{tabular}{#1p{#2}#1}
      \toprule
      \l_DT_header_tl && \l_DT_header_tl \\
      \midrule
      \seq_mapthread_function:NNN
        \l_DT_contents_A_seq
        \l_DT_contents_seq
        \DT_one_row:nn
      \bottomrule
    \end{tabular}
  }
\cs_new:Npn \DT_one_row:nn #1#2 { #1 && #2 \\ }
\ExplSyntaxOff

\begin{document}

\begin{table}
  \centering
  \begin{dbltbl}{cc}{1em}
    thing & mapsto \\
    foo 0 & bar 2 \\
    foo 1 & bar 3 \\
    foo 2 & bar 4 \\
    foo 3 & bar 5 \\
    foo 4 & bar 6 \\
    foo 5 & bar 7 \\
    foo 6 & bar 8 \\
    foo 7 & bar 9 \\
    foo 8 & bar 10 \\
    foo 9 & bar 11 \\
    foo 10 & bar 12 \\
    foo 11 & bar 13 \\
    foo 12 & bar 14 \\
    foo 13 & bar 15 \\
    foo 14 & bar 16 \\
    foo 15 & bar 17 \\
    foo 16 & bar 18 \\
    foo 17 & bar 19 \\
    foo 18 & bar 20 \\
    foo 19 & bar 21 \\
  \end{dbltbl}
  \caption{What is this?}
\end{table}

Pellentesque sed posuere magna. Ut pellentesque dictum posuere. Mauris at justo ipsum. Maecenas sit amet neque erat, nec euismod nisi. Nullam posuere convallis massa vel luctus. Etiam vestibulum semper lectus, sed ultrices leo aliquet sit amet. Vestibulum in lorem vitae magna scelerisque porttitor ut volutpat dui. Nulla risus felis, molestie et tincidunt sit amet, ullamcorper vestibulum erat. Pellentesque bibendum porttitor velit, at tempor erat sollicitudin at. Sed nec nunc lacus. Sed sollicitudin sollicitudin risus sit amet mollis. Nam posuere tincidunt lacus, ut placerat arcu pharetra at. Proin tempus, orci sed consequat consequat, nulla augue tempus augue, vel fermentum mi augue eget odio.

\end{document}
2
  • When compiling your example using latex or pdflatex I get an error: ! This is a LaTeX bug: check coding! ! Command '\seq_set_split:Nnn' not yet defined! Commented May 29, 2012 at 18:49
  • @fuenfundachtzig Update your LaTeX3 install (i.e., the l3kernel, l3packages and l3experimental bundles). \seq_set_split:Nnn was added quite recently (last august). Commented May 30, 2012 at 3:58

You must log in to answer this question.

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