Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Is there maybe a way to define the order of columns oneself?

Say I have

\begin{tabular}{ l l l }
  A1 & C1 & B1 \\
  A2 & C2 & B2 \\
  A3 & C3 & B3 \\
\end{tabular}

but really want

\begin{tabular}{ l l l }
  A1 & B1 & C1 \\
  A2 & B2 & C2 \\
  A3 & B3 & C3 \\
\end{tabular}

and would like to avoid having to move all the content.

share|improve this question
6  
If this is a sometime thing, it's probably fastest to do this in a spreadsheet and then paste it back into your document. If it's a more general thing, then maybe you need something more like the datatool which manipulate CSV data. –  Alan Munn Mar 20 '11 at 0:09

3 Answers 3

up vote 4 down vote accepted

Using @MartinScharrer's rather new collcell package, we can collect the body of each cell and save it with a given label, then typeset the cells in a different order, calling each label. Namely, the code below defines two column types: s{<label>} (for save) and o{<label>} (for output).

One drawback is that you need to put a whole bunch of & at the end of each line to allow typesetting to occur (as many & as you have columns). This can also be used to e.g. double one column, or remove one column.

\documentclass{article}
\usepackage{collcell}
\usepackage{array}

\newcommand{\newcelltoksifnew}[1]{%
  \expandafter\ifx\csname cell@toks@#1\endcsname\relax
  \expandafter\newtoks\csname cell@toks@#1\endcsname
  \fi}
\newcolumntype{s}[1]{%
  >{\unskip\newcelltoksifnew{#1}%
    \collectcell{\global\csname cell@toks@#1\endcsname}}%
  c%
  <{\endcollectcell}%
  @{}%
}
\newcolumntype{o}[1]{%
  >{\the\csname cell@toks@#1\endcsname}%
  c%
}

\begin{document}
\begin{table}\centering
\begin{tabular}{|c|c|c|}
  a  &  c  &  b  \\
AAAAA&CCCCC&BBBBB
\end{tabular}

\begin{tabular}{s{A}s{B}s{C}|o{A}|o{C}|o{B}|}
  a  &  b  &  c  &&&\\
AAAAA&BBBBB&CCCCC&&&
\end{tabular}
\caption{Comparing two tables to see that the spacing is not affected.}
\end{table}

\end{document}
share|improve this answer
1  
Nice idea and implementation! However with simple cells saveboxes could also be used to transfer the content. This would be more efficient then using collcell. –  Martin Scharrer Mar 20 '11 at 11:57
    
Very interesting! I wonder why \newcommand{\as}{&&&} cannot be used to create the many &s at the end of each row... –  Frank Seifert Mar 20 '11 at 15:56
    
@Frank: because collcell would think that \as is part of the content of the cell that it needs to grab. It should be possible to use \newcomand{\amps}{&&} and then &\amps at the end of each line, but that does not seem very nice. –  Bruno Le Floch Mar 20 '11 at 21:31
    
@Martin: you are probably right on using savebox, but I have no experience with boxes, so I wouldn't think about that. –  Bruno Le Floch Mar 20 '11 at 21:32
    
FYI, didn't have luck with &\amps –  Frank Seifert Mar 21 '11 at 1:16

Another method would be to swap to column using a string manipulation package, let's say xstring ;). Of course, swapping 2 columns is not reorder all of them!

The \swapcol command must be written at the begining of every row in which you want to swap the content of 2 cells. The last row must be ended with a \\.

Here is the tricky code:

\documentclass[a4paper]{article}
\usepackage{xstring}
\usepackage{array}
\def\expaddtocs#1#2{%
    \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter
    #1\expandafter\expandafter\expandafter{\expandafter#1#2}}
\def\swapcol#1#2#3\\{%
    \ifnum#1>#2 \def\colinf{#2}\def\colsup{#1}%
    \else \def\colinf{#1}\def\colsup{#2}\fi
    \noexpandarg \let\swaprow\empty \iffalse{\fi\ifnum0=`}\fi
    \expandafter\StrBefore\expandafter[\number\numexpr\colinf-1]{#3&}&[\beforecol]%
    \ifx\beforecol\empty\else\expaddtocs\swaprow{\beforecol&}\fi
    \StrBehind[\colinf]{&#3&}&[\aftercol]%
    \expandafter\StrBefore\expandafter{\aftercol}&[\colA]%
    \expandafter\StrBehind\expandafter{\aftercol}&[\aftercol]%
    \expandafter\StrBefore\expandafter[\number\numexpr\colsup-\colinf-1\expandafter]\expandafter{\aftercol}&[\intercol]%
    \StrBehind[\colsup]{&#3}&[\aftercol]%
    \expandafter\StrBefore\expandafter{\aftercol&}&[\colB]%
    \expandafter\StrBehind\expandafter{\aftercol}&[\aftercol]%
    \expaddtocs\swaprow{\colB&}%
    \ifx\intercol\empty\else\expaddtocs\swaprow{\intercol&}\fi
    \expaddtocs\swaprow{\colA}%
    \ifx\aftercol\empty\else\expaddtocs\swaprow{\noexpand&}\fi
    \expaddtocs\swaprow{\aftercol\\}%
    \ifnum0=`{\fi\iffalse}\fi \swaprow}

\begin{document}
\begin{tabular}{ccccc}
1 & 2 & 3 & 4 & 5 \\
1 & 2 & 3 & 4 & 5 \\
1 & 2 & 3 & 4 & 5 \\
\end{tabular}
\qquad
\begin{tabular}{ccccc}
\swapcol{2}{5}1 & 2 & 3 & 4 & 5 \\
\swapcol{2}{5}1 & 2 & 3 & 4 & 5 \\
\swapcol{2}{5}1 & 2 & 3 & 4 & 5 \\
\end{tabular}

\begin{tabular}{|c|c|c|}
  a  &  c  &  b  \\
AAAAA&CCCCC&BBBBB
\end{tabular}
\qquad
\begin{tabular}{|c|c|c|}
\swapcol{1}{2}  a  &  c  &  b  \\
\swapcol{1}{2}AAAAA&CCCCC&BBBBB\\
\end{tabular}
\end{document}
share|improve this answer

Using the idea from the first solution, but without using collcell:

\def\CollectArg#1\EndCollectArg{\def\StoredContent{#1}}
\newcolumntype{s}[1]{>{\unskip\CollectArg}c%
  <{\EndCollectArg\expandafter\global\expandafter\let\csname StoredColumn#1\endcsname\StoredContent}%
  @{}}
\newcolumntype{o}[1]{>{\csname StoredColumn#1\endcsname}c}

(of course, this requires package array, otherwise newcolumntype is not defined). Typesetting itself is the same as in the first solution.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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