[Tex/LaTex] Selective alignment tabs in tabular/array

arrayshorizontal alignmenttabbingtables

For a while now I've been thinking about an array/tabular feature that would be quite nice to have. It doesn't seem to exist yet, as far as I can discover. And unfortunately, I can't spare the time right now to develop it myself.

If it does exist, please let me know. Otherwise, perhaps someone may be inspired to work on it. If you are so inspired, I'll give you a 300-500 point bounty when you've coded a working solution. Look below.

Feature Description

It involves a new way to indicate content alignment. Rather than using & to jump to the next column, all column separators are assigned a number (or name), and you have to refer to one specifically to align to it, for example with &1, &2, … And \\ always aligns to the right border of the table.

The upshot of all this is that it gives us a very simple syntax for \multicolumn like behavior.

\begin{tabular}{|l|l|l|}                     \hline
    Cell One  &1  Cell Two  &2  Cell Three \\\hline
    Cell One and Two        &2  Cell Three \\\hline
    Cell One  &1  Cell Two and Three       \\\hline
\end{tabular}

would be short for

\begin{tabular}{|l|l|l|}                                    \hline
    Cell One  &  Cell Two                   &  Cell Three \\\hline
    \multicolumn{2}{|l|}{Cell One and Two}  &  Cell Three \\\hline
    Cell One  &  \multicolumn{2}{l|}{Cell Two and Three}  \\\hline
\end{tabular}

It brings a bit of what tabbing does back to our nice modern tabular and array environments. tabbing itself is too simple to be useful in most situations.

Myself, I would use it more for arrays. Being a bit of a perfectionist I've taken to aligning even the smallest bits of my formulas, then using \multicolumn in all formulas that should just pass through that alignment. This contributes positively to the readability of the final document… but not that of the source-code. This feature would help immensely.

Some remarks:

  • A different syntax would be fine. But it should be unobtrusive (i.e. short). David Carlisle has a point: A simple ampersand followed by a bare digit might have a lot of compatibility issues. Something like &'1 or &[1] might be better. (Unless you can enforce that no space occurs between the ampersand and the index. But that would probably involve some big catcode-headaches.)

  • The column specifier that would appear in \multicolumn should, by default, inherit from the main column specification in some sensible way. But we can come up with some nice syntax to override it.

  • I imagine that using alignment tabs out of order should be an error.

  • It should at least be compatible with all the standard functionality of the tabular and array environments. And preferably also with popular packages like array.

Possible Extra Features

  • The ability to create new ad-hoc tab positions. Unlike with tabbing, these should be named and their placement should be decided by their right-most binding — not fixed at their declaration.

  • Simple syntax to jump to a (non ad-hoc) tab position relative to the current one. Such as good-old & to jump to the next. Something like &>2 to jump ahead by 2.

300-500 Point Bounty

As an extra incentive I offer a bounty between 300 and 500 reputation points to the person who writes the package described above. The exact value of the bounty depends on the quality of the package.

I'm not 'officially' placing the bounty on the site yet, because I don't want to impose a one-week deadline. I will place and award the bounty when I've seen and tried the solution.

May the mods strike me down if I don't.


Feedback on David Carlisle's answer

Nice job there! And quick. But there's still some bugs.

Version 0.1

Two separate things go wrong with the following example:

\begin{tabular}{|ll|l|l|}\hline
    Cell One  \>2  Cell Two  \>3  Cell Three  \>4  Cell Four  \<\hline
    Cell One and Two         \>3  Cell Three and Four         \<\hline
    Cell One  \>2  Cell Two, Three and Four                   \<\hline
\end{tabular}
  1. I removed the visible \>2 separator, but this change is also applied for \>3 in the second row.
  2. Oddly, the fourth column doesn't want to be spanned at all.

And (3) the following real-life example doesn't compile at all:

\[
    \begin{array}{l@{{} = {}}l}
        a + (b + c)  \>2  (a + b) + c  \<
        a + b        \>2  b + a        \<
        0 + a = a = a + 0
    \end{array}
\]

Version 0.2

I see you fixed point 2 and 3 from above. Looking good! I can't find a way to break it anymore (right now).

But I'd appreciate it if you could still fix nr. 1. This is the last reason left why I can't use it yet for my real-life documents. (After that there remain only 'would-be-nice' additions.) It needs to handle column separators better. Right now, it uses the column separator from the first column of the preceding cell, whereas it should be using the one from the last column of the preceding cell. Example:

\begin{tabular}{|l||l|l|l|}\hline
    One \>2 Two \>3 Three \>4 Four \<\hline
    One and Two \>3 Three and Four \<\hline
    One and Two and Three \>4 Four \<\hline
    One and Two and Three and Four \<\hline
\end{tabular}

(This bug is not visible in your array example because of a misconception of mine. I imagined that a \< would be implied at the end of the last row. But I don't think this is something that should be fixed. The current behavior is fine.)

Anyway, I'll give you the bounty right now (though I imagine you're not doing this for the 'points'). Still, a fix for that last problem would be great.

Edit: Hehe. Seems you'll have to wait for tomorrow. Silly website. Offering "reward an existing answer" as a valid reason for a bounty, then enforcing a 24 hour waiting period.

Best Answer

enter image description here

\documentclass{article}
\usepackage{array}
\newcount\tc
\makeatletter

\def\x@multispan#1{%
  \begingroup
  \@multicnt#1\relax
  \def\xtmp{}%
  \let\sp@n\relax
  \loop\ifnum\@multicnt>\@ne
   \xdef\xtmp{\xtmp\span\omit}\advance\@multicnt\m@ne\repeat
  \endgroup
  \xtmp}


\protected\def\>#1{%
\ifnum#1>\numexpr\tc+\@ne\relax
\x@multispan{\numexpr#1-\tc}%
\fi
&}

\protected\def\<{%
\ifnum\tabcolnum>\tc\relax
\x@multispan{\numexpr\tabcolnum+\@ne-\tc\relax}%
\fi\\}


\def\@addamp{%
   \ifx\tabcolnum\@undefined
    \tc\@ne
    \edef\@preamble{\@preamble\tc\@ne}%
     \else
    \advance\tc\@ne
     \fi
    \xdef\tabcolnum{\the\tc}%
  \if@firstamp
    \@firstampfalse
    \edef\@preamble{\@preamble\tc\the\tc\relax}%
  \else
    \edef\@preamble{\@preamble &\tc\the\tc\relax}%
  \fi}

\makeatother


\begin{document}



\begin{tabular}{|l|l|l|l|}\hline
    Cell One  \>2  Cell Two  \>3  Cell Three  \>4  Cell Four  \\\hline
    Cell One and Two         \>3  Cell Three and Four         \<\hline
    Cell One  \>2  Cell Two, Three and Four                  \<\hline %hmph
    Cell One  \>2  Cell Two, Three and Four                  \<\hline %ditto
\end{tabular}


\bigskip

\begin{tabular}{|l|l|l|}\hline
    Cell One  \>2  Cell Two  \>3  Cell Three \<\hline
    Cell One and Two       \>3 Cell Three    \<\hline
    Cell One  \>2  Cell Two and Three       \<\hline
\end{tabular}

\bigskip

\[
    \begin{array}{@{}l@{{}={}}l}% The @{} at the start is _required_ for tonight.
        a + (b + c)  \>2  (a + b) + c  \<
        a + b        \>2  b + a        \<
        0 + a = a = a + 0
    \end{array}
\]


\bigskip
\begin{tabular}{|l|>{\bfseries}l|>{\itshape}l|}\hline
    Cell One  \>2  Cell Two  \>3  Cell Three \<\hline
    Cell One and Two       \>3 Cell Three    \<\hline
    Cell One  \>2  Cell Two and Three       \<\hline
\end{tabular}


\bigskip

As discussed in comments you can not omit just the left or just
the right part of the preamble, but by adding dummy columns ypu
can separate the inter-column material from \texttt{@} or \texttt{|}
into a separate column so it is available for spanning cells.

\newcolumntype{^}[1]{@{}l@{#1}}
\begin{tabular}{
@{[A] }
l^{ [B] }
>{\bfseries}l^{ [C] }
l^{[ D] }
l^{ [E]}
}\hline
    Cell One  \>2&  Cell Two  \>4&  Cell Three  \>6&  Cell Four \>8\<\hline
    Cell One and Two         \>4& Cell Three and Four          \>8\<\hline
    Cell One  \>2&  Cell Two, Three and Four                   \>8\<\hline
\end{tabular}

\end{document}

Earlier version

enter image description here

So I used \>{col number} in place of your &colnumber and \< in place of \\. Also I numbered the columns from 1.

I added some array package formatting so that you (and I:-) can tell which cell is picking up which column spec. As written it probably requires array package.

\documentclass{article}
\usepackage{array}
\newcount\tc
\makeatletter

\def\x@multispan#1{%
  \begingroup
  \@multicnt#1\relax
  \def\xtmp{}%
  \let\sp@n\relax
  \loop\ifnum\@multicnt>\@ne
   \xdef\xtmp{\xtmp\span\omit}\advance\@multicnt\m@ne\repeat
  \endgroup
  \xtmp}


\protected\def\>#1{%
\ifnum#1>\numexpr\tc+\@ne\relax
\x@multispan{\numexpr#1-\tc}%
\fi
&}

\protected\def\<{%
\ifnum\tabcolnum>\tc\relax
\x@multispan{\numexpr\tabcolnum+\@ne-\tc\relax}%
\fi\\}


\def\@addamp{%
  \if@firstamp
    \@firstampfalse
    \tc\@ne
    \edef\@preamble{\@preamble\tc\@ne}%
  \else
    \advance\tc\@ne
    \xdef\tabcolnum{\the\tc}%
    \edef\@preamble{\@preamble &\tc\the\tc\relax}%
  \fi}

\makeatother

\begin{document}


\begin{tabular}{|l|l|l|l|}\hline
    Cell One  \>2  Cell Two  \>3  Cell Three  \>4  Cell Four  \\\hline
    Cell One and Two         \>3  Cell Three and Four         \<\hline
    Cell One  \>2  Cell Two, Three and Four                  \<\hline %hmph
    Cell One  \>2  Cell Two, Three and Four                  \<\hline %ditto
\end{tabular}


\bigskip

\begin{tabular}{|l|l|l|}\hline
    Cell One  \>2  Cell Two  \>3  Cell Three \<\hline
    Cell One and Two       \>3 Cell Three    \<\hline
    Cell One  \>2  Cell Two and Three       \<\hline
\end{tabular}

\bigskip

\[
    \begin{array}{@{}l@{{}={}}l}% The @{} at the start is _required_ for tonight.
        a + (b + c)  \>2  (a + b) + c  \<
        a + b        \>2  b + a        \<
        0 + a = a = a + 0
    \end{array}
\]


\bigskip
\begin{tabular}{|l|>{\bfseries}l|>{\itshape}l|}\hline
    Cell One  \>2  Cell Two  \>3  Cell Three \<\hline
    Cell One and Two       \>3 Cell Three    \<\hline
    Cell One  \>2  Cell Two and Three       \<\hline
\end{tabular}

\end{document}