Automatic way to break narrow tables into two columns?

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.)

-
Have a look at tex.stackexchange.com/questions/13895/…. –  lockstep Aug 31 '11 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. –  Peter Grill Sep 11 '11 at 5:46
I think no more than one or two times. And only the header should be repeated. (cf. example) –  fuenfundachtzig Sep 11 '11 at 9:45
Bruno's answer looks good to me. Anything missing from it that you don't accept it? –  Christian May 28 '12 at 21:47
Have you tried it? It doesn't work for me. –  fuenfundachtzig May 29 '12 at 18:48

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:

\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}

-

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
\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.

% 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
\midrule
\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}

-
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! –  fuenfundachtzig May 29 '12 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). –  Bruno Le Floch May 30 '12 at 3:58