10

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.

  • are you sure you want to use a bare digit for the marker (it has all kinds of compatibly issues with numeric cell content)? – David Carlisle Jun 13 '13 at 21:19
  • Nope. I'd be fine with any reasonably unobtrusive syntax. – mhelvens Jun 13 '13 at 21:27
  • I don’t think this is a good idea. You have to keep track in which column you are if you want to switch to the next cell. What if you want to insert a new column? Possibly all numbers had to be adjusted. Even worse for multi-column, where you have to calculate the number of the column after the last multi-column column. The idea with named positions is better (for cases where you don't want to change the number of columns to span in the \multicolumn macro). This is probably best done with something like >{\mark{abc}} in the column specification and \>{abc} in the table itself. – Qrrbrbirlbel Jun 13 '13 at 23:48
  • @Qrrbrbirlbel Indeed. But using names does make the syntax so much bulkier. It would be best to be offered the choice between both. – mhelvens Jun 14 '13 at 7:47
  • Code in my answer updated, incidentally if you want two use names you can use \def\middlecolumn{2} \>\middlecolumn – David Carlisle Jun 14 '13 at 11:43
13
+500

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}
  • Pretty cool. And pretty quick. :-) Although there's still a number of bugs to fix before it becomes usable in practice. I've put the ones I found at the end of my question. Want to have a crack at them? – mhelvens Jun 13 '13 at 22:47
  • 6
    @mhelvens bugs? There may be some undocumented features. I'll have a look. – David Carlisle Jun 13 '13 at 22:57
7

If you don't mind a slightly different syntax and using luatex, you can use Lua tables:

\alignedtable 
  { 
    {
      [1] = "Cell one and two",
      [3] = "Cell three and four"
    },
    { [1] = "Cell One",
      [2] = "Cell Two",
      [3] = "Cell Three",
      [4] = "Cell Four"
     },
     {
      [1] = "Cell one",
      [2] = "Cell two, three, and four"
     }
  }

and delegate the typesetting to lua. For example, here is a ConTeXt implementation (it should be easy to translate it to LaTeX):

\def\alignedtable#1%
    {\ctxcommand{alignedtable({ #1 })}}

\startluacode
  function commands.alignedtable( t ) 
    local max_cols = 0;
    for row = 1,#t do
      for col,value in pairs(t[row]) do
        if col > max_cols then
          max_cols = col
        end
      end
    end
    context.bTABLE() -- Settings can be passed here
      for row = 1, #t do
        context.bTR()
        for col = 1, max_cols do
           if t[row][col] ~= nil then
              local n = max_cols - col + 1
              for m = col + 1, max_cols do
                if t[row][m] ~= nil then
                    n = m - col
                    break
                end
              end
             context.bTD{ nc = n }
             context(t[row][col])
             context.eTD()
            end
        end
        context.eTR()
      end
    context.eTABLE()
  end
\stopluacode

\starttext

\alignedtable 
  { 
    {
      [1] = "Cell one and two",
      [3] = "Cell three and four"
    },
    { [1] = "Cell One",
      [2] = "Cell Two",
      [3] = "Cell Three",
      [4] = "Cell Four"
     },
     {
      [1] = "Cell one",
      [2] = "Cell two, three, and four"
     }
  }

\stoptext

enter image description here

  • Hi! Thanks for your suggestion. But to be frank... I mind both. ;-) Nonetheless, it is valuable to have an alternative solution for those who don't mind. – mhelvens Jun 14 '13 at 16:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.