# Writing a table with equally spaced columns, based on the widest column

Friends, I'm trying to generate a table in which I have all columns equally spaced (same width). In my case, the width for all columns would be the width of the widest column of the table:

\documentclass{article}

\begin{document}

\begin{tabular}{ll}
a & b \\
c & Mary had a little lamb
\end{tabular}

\end{document}


Any hints? :)

-

Well, I've been solving this problem before and I ended with quite a universal solution, see the example (you need to run the code twice to get the correct result):

\documentclass{article}

\usepackage{array}

\makeatletter
\newlength\eqcol@newlen
\newlength\eqcol@oldlen
\let\eqcol@bc\hfil
\let\eqcol@ec\hfil
\let\eqcol@br\hfil
\let\eqcol@el\hfil
\newcolumntype{e}[1]{%
>{\setbox0\hbox\bgroup}#1%
<{\egroup
\ifdim\wd0<\eqcol@newlen\else\global\eqcol@newlen\wd0\fi
\ifdim\wd0<\eqcol@oldlen\else\global\eqcol@oldlen\wd0\fi
\hbox to \eqcol@oldlen{%
\csname eqcol@b#1\endcsname
\box0 %
\csname eqcol@e#1\endcsname
}%
}%
}
\newcount\eqcol@count
\eqcol@oldlen5em\relax
\csname eqcol@def@\romannumeral\eqcol@count\endcsname
}
\def\eqcolWrite{%
\immediate\write\@auxout{%
\gdef\expandafter\noexpand\csname eqcol@def@\romannumeral\eqcol@count\endcsname
{\global\eqcol@oldlen\the\eqcol@newlen\relax}%
}%
\global\eqcol@newlen0pt\relax
}
\let\eqcol@old@tabular\tabular
\let\eqcol@old@endtabular\endtabular
\def\endtabular{\eqcol@old@endtabular\eqcolWrite}
\makeatother

\begin{document}

\begin{tabular}{|el|er|}
\hline
111 & 22 \\\hline
33 & 4444444 \\\hline
\end{tabular}

\begin{tabular}{|ec|er|}
\hline
1 & 22 \\\hline
3 & 4 \\\hline
\end{tabular}

\begin{tabular}{|el|er|}
\hline
111 & 22 \\\hline
33 & 444444 \\\hline
\end{tabular}

$A = \eqcolRead\begin{array}{*3{ec}} 1 & 10000 & 1 \\ 1 & 1 & 1 \end{array}\eqcolWrite$

\end{document}


The tabular environment is tweaked by default, in other cases, you have to do it manually (see the array example above).

-

This is inspired by tohecz, but uses a dedicated environment, which I believe is better.

In a equalizedtabular one can use any column specifier, not just L, C or R, but of course only these will be equalized. Two passes are necessary, since the .aux file is used, and upon inclusion of an equalizedtabular between two of them the first compilation will give wrong results; however, the next run of LaTeX will fix the lengths.

\documentclass{article}

\usepackage{array,collcell}

\newcolumntype{C}{>{\collectcell\docellC}c<{\endcollectcell}}
\newcolumntype{L}{>{\collectcell\docellL}c<{\endcollectcell}}
\newcolumntype{R}{>{\collectcell\docellR}c<{\endcollectcell}}

\makeatletter
\providecommand{\@nameedef}[1]{\expandafter\edef\csname#1\endcsname}
\newcommand{\docell}[2]{%
\sbox\equalizedtablebox{#2}%
\ifdim\wd\equalizedtablebox>\@nameuse{finallen\theequalizedtable}\relax
\global\@nameedef{finallen\theequalizedtable}{\the\wd\equalizedtablebox}%
\fi
\makebox[\@nameuse{startinglen\theequalizedtable}][#1]{#2}%
}
\newcommand{\docellC}[1]{\docell{c}{#1}}
\newcommand{\docellL}[1]{\docell{l}{#1}}
\newcommand{\docellR}[1]{\docell{r}{#1}}
\newcounter{equalizedtable}
\newsavebox\equalizedtablebox
\newenvironment{equalizedtabular}[2][c]
{%
\stepcounter{equalizedtable}%
\global\@namedef{finallen\theequalizedtable}{0pt}%
\@ifundefined{startinglen\theequalizedtable}
{\@namedef{startinglen\theequalizedtable}{5em}}{}
\tabular[#1]{#2}%
}
{%
\endtabular
\begingroup\edef\x{\endgroup
\write\@auxout{%
\global\noexpand\noexpand\noexpand\@namedef{startinglen\theequalizedtable}%
{\@nameuse{finallen\theequalizedtable}}%
}}\x
}
\makeatother
\begin{document}

\begin{equalizedtabular}{|L|C|}
\hline
111 & 22 \\\hline
33 & 4444444 \\\hline
\end{equalizedtabular}

\begin{equalizedtabular}{|R|C|}
\hline
111 & 22 \\\hline
33 & 4 \\\hline
\end{equalizedtabular}

\end{document}


-

I'd change the input syntax a bit:

\documentclass{article}

\makeatletter
\def\paulo#1{\count@#1\relax\leavevmode\setbox\z@\vbox\bgroup}
\def\endpaulo{\egroup\dimen@\wd\z@\global\setbox\@ne\null
\setbox\z@\vbox{\unvbox\z@\loop\unskip\unskip\setbox\z@\lastbox
\ifvoid\z@\else
\global\setbox\@ne\hbox{\hbox to\dimen@{\box\z@\hfil}\penalty\z@\unhbox\@ne}%
\repeat}%
\vbox{\hsize\count@\dimen@\noindent\unhbox\@ne}}

\def\cell#1{\hbox{\kern\tabcolsep\ignorespaces#1\unskip\kern\tabcolsep}}

\makeatother
\begin{document}

\begin{paulo}{2}
\cell{a}
\cell{b}
\cell{c}
\end{paulo}

\end{document}

-

If you know the entry of the widest column, the solution may be as the following:

\documentclass{article}
\begin{document}
\newlength{\thicklamb}
\begin{tabular}{p{\thicklamb}p{\thicklamb}}
a & b \\
c & Mary had a little lamb
\end{tabular}

\end{document}


-

This answer picks up a bit from egreg's answer and a lot from the eqparbox package.

\documentclass{article}

\usepackage{array}
\usepackage{eqparbox}

\makeatletter
\newcounter{eqtabular}
\newsavebox\eqtabularbox

\newcolumntype{C}{>{\begin{lrbox}{\eqtabularbox}}c<{\end{lrbox}%
\eqmakebox [\the\c@eqtabular @eqtabular]%
{\unhcopy\eqtabularbox}}}
\newcolumntype{L}{>{\begin{lrbox}{\eqtabularbox}}c<{\end{lrbox}%
\eqmakebox [\the\c@eqtabular @eqtabular][l]%
{\unhcopy\eqtabularbox}}}
\newcolumntype{R}{>{\begin{lrbox}{\eqtabularbox}}c<{\end{lrbox}%
\eqmakebox [\the\c@eqtabular @eqtabular][r]%
{\unhcopy\eqtabularbox}}}

\newenvironment{eqtabular}[2][c]
{%
\stepcounter{eqtabular}%
\tabular[#1]{#2}%
}
{%
\endtabular
}
\makeatother

\begin{document}\thispagestyle{empty}

\begin{eqtabular}{|L|L|}
\hline
111 & 22 \\\hline
33 & 4444444 \\\hline
\end{eqtabular}

\begin{eqtabular}{|R|R|}
\hline
111 & 22 \\\hline
33 & 4444444 \\\hline
\end{eqtabular}

\begin{eqtabular}{|C|C|}
\hline
11111111111 & 22 \\\hline
33 & 4444444 \\\hline
\end{eqtabular}

\begin{eqtabular}{|R|L|}
\hline
11111111111 & 22 \\\hline
33 & 4444444 \\\hline
\end{eqtabular}

\begin{eqtabular}{|R|C|}
\hline
111 & 22 \\\hline
33 & 4 \\\hline
\end{eqtabular}

\begin{eqtabular}{|L|R|}
\hline
111 & 22 \\\hline
33 & 4 \\\hline
\end{eqtabular}

\end{document}


-
at least two latex runs are necessary. – jfbu Oct 20 '13 at 21:28
I would prefer \unhbox over \unhcopy since you won't need the box again ;) – yo' Oct 21 '13 at 6:18
@tohecz yes, you are right, I copied-pasted from some other code I had in my files. I will fix it. Actually the box is erased from memory as the tabular character or the newline closes a group, (if I am correct), so the change is a bit cosmetic (I think). – jfbu Oct 21 '13 at 6:38
@tohecz see where my infinite trust in you has led me ? ;-) actually, no it doesn't work with \unhbox. It's too early for me in the morning to try to understand that, I hastily re-edited to revert my changes... – jfbu Oct 21 '13 at 6:44
@tohecz I now recall that it is not from my files but from an example in the eqparbox documentation that I got the \unhcopy. Quick look at the code makes me think there is \eqp@settowidth which does a \settowidth on the material and then \eqp@produce@box which uses a second time the material to actually print the box. So \unhbox is not usable within an eqparbox box construct. – jfbu Oct 21 '13 at 6:58

needs at least two runs:

\documentclass{article}
\usepackage{array}
\newsavebox\CBox \sbox\CBox{ }
\makeatletter
\@ifdefinable\CWidth{\def\CWidth{1em}}% for the first latex run
\newcolumntype{P}{
>{\sbox\CBox\bgroup}%         start to save the contents
p{\CWidth}%                  set the column to the maximal width
<{\egroup%                    end of the savebox
\ifdim\the\wd\CBox>\CWidth% is the width bigger than the current one
\immediate\write\@mainaux{\gdef\string\CWidth{\the\wd\CBox}}\fi%
\usebox\CBox}}%             write contents into the cell
\makeatother
\begin{document}

\begin{tabular}{|P|P|}\hline
a & b \\\hline
c & Mary had a little lamb\\\hline
\end{tabular}

\end{document}


-
\sbox\CBox\bgroup...\egroup expands to \setbox\CBox=\hbox{\color@setgroup\bgroup\color@endgroup#2}\egroup which is not what's wanted. – egreg Oct 21 '13 at 7:46
how do you know what I want?? – Herbert Oct 21 '13 at 7:54
Everybody can see you're losing the protection for colors. You're free to use bad macros, if so pleases you, but at least warn users about the risks. – egreg Oct 21 '13 at 8:06
A hack would be to say \sbox\CBox\bgroup\aftergroup, so that \color@endgroup will be executed after the brace, keeping the color stack in sync. – egreg Oct 21 '13 at 8:46

This is as good a place as any to pre-introduce the new package I'm working on: tabstackengine, which is a front end to my stackengine package to provide support for tabbed arguments. The reason I introduce the package here is because it supports fixed-width tabbing (based on the widest argument) WITH A SINGLE COMPILER PASS, which is the topic of this question. To do that, one sets the mode \fixTABwidth{T} or \fixTABwidth{F} before the macro invocation.

With a few exceptions where it doesn't make sense, you can take a stackengine macro and add the word tabbed, align or tabular before it to create a tabbing version of a stackengine macro. The syntax is

\tabbedstackengine_macro[stackengine_optional_arg.]tabbed_stackengine_argument(s)

\alignstackengine_macrotabbed_stackengine_argument(s)

\tabularstackengine_macro{column alignments}tabbed_stackengine_argument(s)

The tabbed versions provides columns, each tabbed to the same alignment; the align versions provide {rlrl...} alignment; while the tabular versions provide user-specified alignments.

I don't support \hlines between rows, or even vertical line separators (after all, if you really want a tabular, just use tabular), but I do provide specifiable gap widths between adjacent columns, if desired (defaults to 0pt for tabbed macros, to 1em [ equal to a "quad"] for align commands, and \tabcolsep for tabular commands).

The default alignment tabs are the & char, but that can be changed. The default EOL is \\, but that can be changed.

The one exception I employ in the naming convention is for stackengine's \xxxVectorstack macros, which are named, for the tabbed versions, \xxxMatrixstack.

Package is now available at http://ctan.org/pkg/tabstackengine

Below is the MWE employing the package:

\documentclass{article}
\RequirePackage{tabstackengine}
\parskip0.8em\parindent0em
\begin{document}

Setting fixed tab width.
\fixTABwidth{T}
Setting default tabular inter-item gap to 0pt
\setstacktabulargap{0pt}

tabbedShortstack[l]:\    \framebox{\tabbedShortstack[l]{a & bb & ccc & dddd\      1&2&3&$\displaystyle\frac{x}{y}$ \\This&is&a&test}}

tabbedShortstack[c]:\    \framebox{\tabbedShortstack[c]{a & bb & ccc & dddd\      1&2&3&$\displaystyle\frac{x}{y}$ \\This&is&a&test}}

tabularShortstack\{lccr\}:\    \framebox{\tabularShortstack{lccr}{a & bb & ccc & dddd\      1&2&3&$\displaystyle\frac{x}{y}$ \\This&is&a&test}}

Setting default tabbed inter-item gap to 1ex
\setstacktabbedgap{1ex}

$\vertMatrixstack[c]{% x_{11} & x_{12} & x_{13}\ x_{21} & x_{22} & x_{23}\ x_{31} & x_{32} & x_{33}}$

$\bracketMatrixstack[c]{% x_{11} & x_{12} & x_{13}\ x_{21} & \mathbf{X_{22}} - x_{22} & x_{23}\ x_{31} & x_{32} & x_{33}}$

Setting to natural tab width.
\fixTABwidth{F}

$\bracketMatrixstack[c]{% x_{11} & x_{12} & x_{13}\ x_{21} & \mathbf{X_{22}} - x_{22} & x_{23}\ x_{31} & x_{32} & x_{33}}$

tabbedstackon:\    \tabbedstackon{a & bb & ccc& dddd}{1&2&3&4}

Setting fixed tab width.
\fixTABwidth{T}

\tabbedstackon{a & bb & ccc& dddd}{1&2&3&4}

Setting default align inter-item gap to 1ex\    \setstackaligngap{1ex}
alignVectorstack:\    \vert A\vert = \left|\alignVectorstack{ 3.&21 & 4.&3 & 1.& \ 1.&1 &432.&2 &13.&3\ 56.&83 & 37.&27 &67.&37} \right|

\end{document}}


-
Thank you Steven! I can't wait until your package hits CTAN! :) – Paulo Cereda Oct 24 '13 at 16:07
@PauloCereda It has arrived: ctan.org/pkg/tabstackengine – Steven B. Segletes Feb 20 '14 at 20:47
yay, congrats! :) – Paulo Cereda Feb 20 '14 at 21:45