2

tabular sets column widths to the widest element across all rows.

Is it possible to set two or more separate tabulars to consider each other's column widths and pick the largest of the them?

For example, if I break a tabular with additional paragraph text and want to continue the tabular as if it were a longtable crossing onto the next page (same column widths, possibly reiterating the headers), would this be possible?

Werner
  • 603,163
kando
  • 1,338
  • 2
    Isn't it easier to used fixed lengths for tabulars then? –  Jun 08 '16 at 16:27
  • Would the cells in both tabular be one-line only? – Bernard Jun 08 '16 at 16:37
  • @ChristianHupfer Autosize for the win. I hate specifying widths; I'm looking for a robust solution. – kando Jun 08 '16 at 17:26
  • @Bernard Do you mean single row tabulars or do you mean each row is always equal to 1em without increases from equations, multirow, or anything else? Either way: no. I'm looking for a robust solution which can handle anything. – kando Jun 08 '16 at 17:28
  • 2
    I just mean: will your cells have line breaks, whether automatic or not? – Bernard Jun 08 '16 at 17:36
  • Would you accept a solution based on the \halign TeX primitive? I mean, are you ready to accept a not-so-user-friendly syntax for specifying the alignment of columns? – GuM Jun 08 '16 at 21:46
  • It can be done, and oddly enough is is based on http://tex.stackexchange.com/questions/277901/remove-specific-column-from-multiple-tables/277958?s=1|1.4417#277958. – John Kormylo Jun 09 '16 at 02:33

2 Answers2

2

The idea is to create a bunch of special column types such that every time this column type appears in a tabular it will always have the same width. This requires 2 runs of the document, where the widths computed in the first run are saved in the aux file.

Note: If you ever want to make the columns narrower, you will need to delete the aux file or at least comment out the \AtEndDocument.

\documentclass{article}
\usepackage{array}

\newsavebox{\tempbox}% \box0 etc. used

\makeatletter
\newcommand{\saveWidth}[1]% #1=column name (A,B,...)
{\immediate\write\@auxout{\string\initWidth{#1}{\the\csname Width#1\endcsname}}}

\newcommand{\initWidth}[2]% #1=column name (A,B,...), #2=the width
{\@ifundefined{Width#1}{}{\global\csname Width#1\endcsname=#2\relax}}
\makeatother

\newlength{\WidthA}% one for each column type
\newlength{\WidthB}
\newlength{\WidthC}

\AtEndDocument{\saveWidth{A}\saveWidth{B}\saveWidth{C}}

\newcolumntype{A}{>{\savebox{\tempbox}\bgroup}{l}<{\egroup%
  \ifdim\wd\tempbox>\WidthA \global\WidthA=\wd\tempbox\fi%
  \makebox[\WidthA][l]{\usebox\tempbox}}}

\newcolumntype{B}{>{\savebox{\tempbox}\bgroup}{c}<{\egroup%
  \ifdim\wd\tempbox>\WidthB \global\WidthB=\wd\tempbox\fi%
  \makebox[\WidthB][c]{\usebox\tempbox}}}

\newcolumntype{C}{>{\savebox{\tempbox}\bgroup}{r}<{\egroup%
  \ifdim\wd\tempbox>\WidthC \global\WidthC=\wd\tempbox\fi%
  \makebox[\WidthC][r]{\usebox\tempbox}}}

\begin{document}
\noindent\begin{tabular}{ABC}
left & center & right\\
wide left & wide center  & wide right
\end{tabular}

\medskip
Some text here.
\medskip

\noindent\begin{tabular}{ABC}
left & center & right\\
\end{tabular}

\medskip
Some text here.
\medskip

\noindent\begin{tabular}{ABC}
very wide left & very wide center & very wide right\\
\end{tabular}

\end{document}

To make it easier to create new columns, I added \newcolumnwidth{<name>}{l/c/r} (which is itself rather ugly).

\newcommand{\newcolumnwidth}[2]% #1=new column type, #2=l/c/r
{\expandafter\newlength\csname Width#1\endcsname%
 \AtEndDocument{\saveWidth{#1}}%
 \newcolumntype{#1}{>{\savebox{\tempbox}\bgroup}{#2}<{\egroup%
  \ifdim\wd\tempbox>\csname Width#1\endcsname \global\csname Width#1\endcsname=\wd\tempbox\fi%
  \makebox[\csname Width#1\endcsname][#2]{\usebox\tempbox}}}}

\newcolumnwidth{A}{l}
\newcolumnwidth{B}{c}
\newcolumnwidth{C}{r}
John Kormylo
  • 79,712
  • 3
  • 50
  • 120
1

The approach I would follow is similar to what is done inside the tabbing environment. You set a first row that defines the tab stops and then \kill that row so it doesn't show. Subsequent rows will use these tab stops without the first row being present.

enter image description here

\documentclass{article}

\begin{document}

\noindent
\begin{tabular}{l c r}
  left      & center      &      right \\
  wide left & wide center & wide right
\end{tabular}

\medskip

Some text here.

\medskip

\noindent
\begin{tabular}{l c r}
  \phantom{wide left} &
    \phantom{wide center} & 
    \phantom{wide right} \\[-\normalbaselineskip]% Similar to \kill
  left      & center      &      right
\end{tabular}

\end{document}

The "\kill row" in the above example places the widest elements across both of your tables inside a \phantom, while the height of the row is removed using a newline of the form \\[-\normalbaselineskip].

If the content to be hidden is very tall, use \hphantom. If you're concerned about overprinting of vertical rules, don't use them (as suggested by the awesome booktabs) or insert each column element in the "\kill row" using \multicolumn{1}{l}{...} without vertical rules.

Werner
  • 603,163