4

I have created the following macro for Table:

\newcommand{\createtable}[7]{
\begin{table}[htbp]
\begin{tabular}{|p{8cm}||p{8cm}|}
\hline
\begin{center}\textbf{\cellcolor{Orchid!25}{#1}}\end{center} &
\begin{center}\textbf{\cellcolor{Orchid!25}{#2}}\end{center} \\
\hline\hline
 {#3} 
 & {#4}\\
 \hline
 {#5}
 & {#6}\\ 
\hline
    \end{tabular}%
 \centering
 \caption{#7}
\end{table}
}

Usage:

\createtable
    {Label1} 
    {Label2}
    {Text1-1}
    {Text2-1}
    {Text1-2}
    {Text2-2}
    {Table Title}

Output:

enter image description here

Problem:

Reference: \newcommand with optional multi-line argument and implicit itemize environment

Here, we can create a dynamic bullet list, without any prior knowledge of the number of items.

I need a similar macro for tables, so that if I write:

\createtable
  {Label1}
  {Label2}
  {Label3}
  {Text1-Label1
   \&
   Text1-Label2
   \&
   Text1-Label3
   \\
   Text2-Label1
   \&
   Text2-Label2
   \& 
   Text2-Label3
}   

The macro should be intelligent enough to figure out that:

[1] Table has 3 columns -- Label1, Label2 and Label3
[2] Distribute the text-input separated by \& among these columns, i.e. 
   Text1-Label1 under Label1, Text1-Label2 under Label2 and Text1-Label3 under Label3

[3] Identify the end of row marker as "//"
    and add further entries (using the procedure described in 
    point [2]) to the next row. 

Can anyone please provide some pointers.

This is what I tried initially:

\ExplSyntaxOn
\NewDocumentCommand{\testtable}{ m o }
{
  % split the \\ separated list of items
  \seq_set_split:Nnn \l_egreg_outline_items_seq { \\ } { #1 }
\begin{tabular}{|p{8cm}||p{8cm}|}
\hline
\begin{center}\textbf{\cellcolor{Orchid!25}{Column1}}\end{center} &
\begin{center}\textbf{\cellcolor{Orchid!25}{Column2}}\end{center} \\
\hline\hline
  \seq_map_inline:Nn \l_egreg_outline_items_seq
   {
    ##1 %\hline
   }
    \end{tabular}%
}
\ExplSyntaxOff

If we can't provide number of columns at run-time, that is ok, but number of rows should be added dynamically.

6
  • The solution is somehow indicated in the linked question: Use \NewDocumentCommand and lists.
    – user31729
    Commented Apr 18, 2015 at 6:25
  • Yes, but that is more 'horizontally' oriented, I am running into problems because of columns Commented Apr 18, 2015 at 6:41
  • 2
    You are asking for a lot of cleverness, but how much? Will this macro sometimes create two-column tables and other times five-column tables? Also: why can't the macro specify explicitly how many columns there will be? Fiinally, I can't help but wonder if a .csv-driven approach (using either datatool or csvsimple) wouldn't be a way easier method to do what you want. These macros will probably be extremely brittle....
    – jon
    Commented Apr 18, 2015 at 6:47
  • ok, if we keep number of columns as predefined, can we keep number of rows variable? I have added my initial code and updated question about fix columns Commented Apr 18, 2015 at 7:03
  • Where's the data for the table coming from? Is it generated from another source?
    – jon
    Commented Apr 18, 2015 at 7:30

2 Answers 2

5

I suggest the usage of \createtable as follows:

\createtable 3 {3cm}
  {Label1}        {Label2}       {Label3}
  {Text1-Label1 | Text1-Label2 | Text1-Label3 |
   Text2-Label1 | Text2-Label2 | Text2-Label3 }
  {Table title}

You can see that you must specify the number of columns (3 in the example) and the width of columns (3cm in the example). You are using a fixed column width in your example, so there is a good reason to specify it.

The implementation should be:

\newcount\tmpnum   
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}

\def\createtable#1#2{\def\tabcols{#1}\def\colwidth{#2}%
   \def\tabdata{}\def\tabdataA{}\tmpnum=0 \createtableA}
\def\createtableA#1{\advance\tmpnum by1
   \addto\tabdata{\begin{center}\textbf{\cellcolor{red!25}{#1}}\end{center}}%
   \addto\tabdataA{|p{\colwidth}|}%
   \ifnum\tabcols>\tmpnum
      \addto\tabdata{&}\expandafter\createtableA
   \else
      \addto\tabdata{\\ \hline\hline}\expandafter\createtableB
   \fi
}
\def\createtableB#1{\tmpnum=0 \createtableC#1||}
\def\createtableC#1|{\ifx|#1|\expandafter\createtableD\else   
   \advance\tmpnum by1
   \ifnum\tabcols=\tmpnum \addto\tabdata{{#1}\\ \hline}\tmpnum=0
   \else \addto\tabdata{{#1}&}%
   \fi
   \expandafter\createtableC \fi
}
\def\createtableD#1{%
   \begin{table}[htbp]
   \edef\tmp{\noexpand\begin{tabular}{\tabdataA}}\tmp
   \hline
   \tabdata
   \end{tabular}
   \centering\caption{#1}
   \end{table}
}
5

If you input the labels in a unique argument, it's easy to figure out the number of columns.

\documentclass{article}
\usepackage{xparse}
\usepackage[table]{xcolor}
\usepackage{tabularx}
\usepackage{booktabs}

\ExplSyntaxOn
\NewDocumentCommand{\createtable}{mm}
 {
  \sandeep_ct_create_table:nn { #1 } { #2 }
 }

\int_new:N \l_sandeep_ct_cols_int
\seq_new:N \l_sandeep_ct_head_input_seq
\seq_new:N \l_sandeep_ct_head_output_seq
\seq_new:N \l_sandeep_ct_table_body_seq

\cs_new_protected:Npn \sandeep_ct_create_table:nn #1 #2
 {
  \seq_set_split:Nnn \l_sandeep_ct_head_input_seq { & } { #1 }
  \int_set:Nn \l_sandeep_ct_cols_int
   {
    \seq_count:N \l_sandeep_ct_head_input_seq
   }
  \seq_set_map:NNn \l_sandeep_ct_head_output_seq \l_sandeep_ct_head_input_seq
   {
    \exp_not:n { \multicolumn{1}{c}{\ctbigstrut\bfseries ##1} }
   }
  \seq_set_split:Nnn \l_sandeep_ct_table_body_seq { \\ } { #2 }
  \begin{tabularx}{\columnwidth}{*{\l_sandeep_ct_cols_int}{X}}
  \toprule
  \addlinespace[0pt]
  \rowcolor{orchid}
  \seq_use:Nn \l_sandeep_ct_head_output_seq { & } \\
  \addlinespace[0pt]
  \midrule
  \seq_use:Nn \l_sandeep_ct_table_body_seq { \\ \addlinespace }
  \\
  \bottomrule
  \end{tabularx}
 }

\ExplSyntaxOff

\newcommand{\ctbigstrut}{%
  \vrule height .8cm
         depth \dimexpr.8cm-\ht\strutbox\relax
         width 0pt
}

\definecolor{orchid}{RGB}{242,213,230}

\begin{document}

\noindent
\createtable
 {
  Label 1 & Label 2
 }
 {
  Text1-Label1
  &
  Text1-Label2
  \\
  Text2-Label1
  &
  Text2-Label2
}   

\bigskip

\noindent
\createtable
 {
  Label 1 & Label 2 & Label 3
 }
 {
  Text1-Label1
  &
  Text1-Label2
  &
  Text1-Label3
  \\
  Text2-Label1
  &
  Text2-Label2
  & 
  Text2-Label3
 }

\end{document}

The first argument is split at & to count the number of columns; the items are then put as the argument of \multicolumn.

Then we split the table body at \\ in order to be able to add \addlinespace between rows.

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .