# Generating a table based on a list and a number of columns

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.

-
The problem with the answers is which to pick as the accepted one :D. – Willem Van Onsem Jun 16 '14 at 17:28

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\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}

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

-

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}

-