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.

Sometimes a table is used to compact a large number of items.

Example:

a b c d
e f g h
j k l

Instead of listing all items separately.

We want to define a command that eases the implementation of this (say you want to insert an item i, you don't want to do all the bookkeeping to make the items match again).

We want to define a command \compacttable{cccc}{a,b,c,d,e,f,g,h,j,k,l} that displays such tables.

We tried the following definition:

\usepackage{tikz,ifthen,xstring,etoolbox}

\newcounter{col}
\newcommand{\compacttable}[2]{
    \setcounter{colc}{1}\StrLen{#1}[\imresl]
    \def\temp{}
    \foreach\tx in{#2}{
    \ifthenelse{\equal{\imresl}{\value{colc}}}{
        \setcounter{colc}{1}\expandafter\gdef\expandafter\temp\expandafter{\temp \tx \\}
    }{
        \stepcounter{colc}\expandafter\gdef\expandafter\temp\expandafter{\temp \tx & }
    }}
    \begin{tabular}{#1}
    \temp{}
    \end{tabular}
}

However the MWE fails to show any values:

main.tex:

\documentclass{article}
\usepackage{tikz,ifthen,xstring,etoolbox}
\newcounter{col}
\newcommand{\compacttable}[2]{
    \setcounter{colc}{1}\StrLen{#1}[\imresl]
    \def\temp{}
    \foreach\tx in{#2}{
    \ifthenelse{\equal{\imresl}{\value{colc}}}{
        \setcounter{colc}{1}\expandafter\gdef\expandafter\temp\expandafter{\temp \tx \\}
    }{
        \stepcounter{colc}\expandafter\gdef\expandafter\temp\expandafter{\temp \tx & }
    }}
    \begin{tabular}{#1}
    \end{tabular}
}
\begin{document}
\compacttable{cccc}{a,b,c,d,e,f,g,h,j,k,l}
\end{document}

We think this is due to the fact that \tx does not bind when we try to expand \temp.

share|improve this question
    
The problem with the answers is which to pick as the accepted one :D. –  CommuSoft Jun 16 at 17:28

3 Answers 3

up vote 5 down vote accepted

Without additional packages and using a token list which can easily add ans kind of TeX tokens:

\documentclass{article}
\newcounter{col} \newcounter{maxcol} \newtoks\myTab
\makeatletter
\newcommand\addtabtoks[1]{\myTab\expandafter{\the\myTab#1}}
\newcommand\compacttable[2]{%
  \setcounter{col}{0}\setcounter{maxcol}{#1}%
  \myTab{\tabular{*#1c}}%                       Initial setting
  \compacttable@i#2,,\@nil}
\def\compacttable@i#1,#2,#3\@nil{%
  \stepcounter{col}%
  \ifnum\thecol<\themaxcol\addtabtoks{ #1 & }%  Default column
  \else \addtabtoks{#1 \\}\setcounter{col}{0}\fi% start new line
  \ifx\relax#2\relax \the\myTab\endtabular%     Output of list and \endtabular  
  \else \compacttable@i#2,#3\@nil\fi}
\makeatother
\begin{document}
\compacttable4{a,b,c,d,e,f,g,h,j,k,l}
\fbox{\compacttable3{a,b,c,d,e,f,g,h,j,k,l}}
\end{document}

enter image description here

share|improve this answer
    
Probably the last command before \begin{document} should be replaced by \makeatother? –  CommuSoft Jun 18 at 23:22
    
yes, thanks ... –  Herbert Jun 19 at 6:41
    
Another question: why does \myTab{\tabular{*#1c}\toprule} doesn't work (with the booktabs) package? –  CommuSoft Jun 19 at 9:26
    
"doesn't work" is not a useful error description ... I have no problem with that code. –  Herbert Jun 19 at 9:43
    
Sorry, We figured out it was a side effect of other commands. Many thanks. –  CommuSoft Jun 19 at 11:55

As you point out the problem is due to expansion. You could just do:

\expandafter\expandafter\expandafter\gdef\expandafter\expandafter\expandafter\temp\expandafter\expandafter\expandafter{\expandafter\temp\tx & }%

However, to improve readability defining an intermediate macro to reduce the multiple uses of \expandafter is possible as shown below. In addition, the code needs to have % after many of the lines ending in { and } to prevent spaces being inserted into the document.

\documentclass[border=5]{standalone}
\usepackage{pgffor,ifthen,xstring}
\newcounter{colc}
\def\globalappendtomacro#1#2{%
  \expandafter\gdef\expandafter#1\expandafter{#1#2}%
}
\newcommand{\compacttable}[2]{%
    \setcounter{colc}{1}%
    \StrLen{#1}[\imresl]%
    \def\temp{}%
    \foreach\tx in{#2}{%
      \ifthenelse{\equal{\imresl}{\value{colc}}}{%
        \setcounter{colc}{1}%
        \expandafter\globalappendtomacro\expandafter\temp\expandafter{\tx \\}%
    }{%
        \stepcounter{colc}%
        \expandafter\globalappendtomacro\expandafter\temp\expandafter{\tx &}%
     }}%
    \begin{tabular}{#1}
      \temp
    \end{tabular}%
}

\begin{document}
\framebox{\compacttable{cccc}{a,b,c,d,e,f,g,h,j,k,l}}
\end{document}

enter image description here

share|improve this answer

Here's an expl3 implementation; save the input in a sequence annd do a mapping; if the column count is equal to the specified number of columns, add \\ and zero the column counter, otherwise just add &.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\compacttable}{ m m }
 {
  \commusoft_compact_table:nn { #1 } { #2 }
 }

\int_new:N \l__commusoft_col_int
\tl_new:N \l__commusoft_table_body_tl
\seq_new:N \l__commusoft_input_seq

\cs_new_protected:Npn \commusoft_compact_table:nn #1 #2
 {
  \tl_clear:N \l__commusoft_table_body_tl
  \int_zero:N \l__commusoft_col_int
  \seq_set_split:Nnn \l__commusoft_input_seq { , } { #2 }
  \seq_map_inline:Nn \l__commusoft_input_seq
   {
    \int_incr:N \l__commusoft_col_int
    \int_compare:nTF { \l__commusoft_col_int == #1 }
     {
      \tl_put_right:Nn \l__commusoft_table_body_tl { ##1 \\ }
      \int_zero:N \l__commusoft_col_int
     }
     {
      \tl_put_right:Nn \l__commusoft_table_body_tl { ##1 & }
     }
   }
  \begin{tabular}{*{#1}{c}}
  \l__commusoft_table_body_tl
  \end{tabular}
 }
\ExplSyntaxOff

\begin{document}

\compacttable{4}{a,b,c,d,e,f,g,h,j,k,l}

\compacttable{5}{a,b,c,d,e,f,g,h,i,j,k,l,m}

\end{document}

enter image description here

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.