3

In my thesis I have a table that I want to build up over the course of a chapter. Specifically, I am presenting statistics about different datasets, including one that I created myself to address issues in the existing data.

Ideally I would write the table+tabular code once and then refer to that code everywhere the table needs to be repeated, just revealing or hiding different parts of it.

So I might write:

   \begin{table}
     \caption{Sample Table}
     \label{tab:sample-table}
     \begin{tabular}{lr}
       dataset & some numbers\\
       \hline
       A & 10\\
       B & 11\\
       C & 12\\
       \hline
       D & 48\\
       E & 144\\
     \end{tabular}
   \end{table}

And then in one place use some command like:

   \inserttable[1-4]{tab:sample-table}

to insert the header & rows A-C, and in another place write:

   \inserttable{tab:sample-table}

in order to insert the whole table.

Is there any package or set of macros for doing this or do I have to repeat the table every place that I want to reference it?

My table is quite a bit larger and more complex than this, and my concern is that if I have to update some of the values I might update them in one place and forget the others if I have to duplicate the code.

3

Here is one way to do this. First define the entries of the entire table:

\newcommand*{\MyTabularEntries}{%
   Row & dataset & some numbers \\,
   \unexpanded{\cmidrule(r){1-1}\cmidrule(lr){2-2}\cmidrule(l){3-3}},
   3 & A & 10 \\,
   4 & B & 11 \\,
   5 & C & 12 \\,
   \unexpanded{\cmidrule{1-3}},
   7 & D & 48 \\,
   8 & E & 144 \\,
}%

and then build the table with only the dried rows by invoking

\InsertTable[<csv list of rows>]{<title>}{\MyTabularEntries}

enter image description here

Notes:

  • I added a row number to make it easier to see that this solution is working correctly. The header and cmidrule are counted.
  • I also used the booktabs package as that produces better tables.

References

Code:

\documentclass{article}
\usepackage{etoolbox}
\usepackage{booktabs}
\usepackage{xparse}
\usepackage{tikz}

\newcommand*{\MyTempTableTokens}{}%
\makeatletter
    \newtoks\@tabtoks
    %%% assignments to \@tabtoks must be global, because they are done in \foreach
    \newcommand\AddTableTokens[1]{\global\@tabtoks\expandafter{\the\@tabtoks#1}}
    \newcommand\eAddTableTokens[1]{%
      \protected@edef\MyTempTableTokens{#1}%
      \expandafter\AddTableTokens\expandafter{\MyTempTableTokens}%
    }
    %%% variable should always be operated on always locally or always globally
    \newcommand*\ResetTableTokens{\global\@tabtoks{}}
    \newcommand*\PrintTableTokens{\the\@tabtoks}

%% \processlist is based on a contribution by Hood Chatham
\newcount\tempcount
\newcommand*{\MacroToExecute}{}%
\def\processlist#1#2{\def\MacroToExecute{#1}\processlist@#2,\@nil}
\def\processlist@#1,{%
    \in@-{#1}%
    \ifin@
        \processrange#1\@nil
    \else
        \MacroToExecute{Row #1}{}%
    \fi
    \@ifnextchar\@nil{\@gobble}{\processlist@}%
}

\def\processrange#1-#2\@nil{%
    \tempcount=#1\relax
    \loop
        \MacroToExecute{Row \the\tempcount}{}%
        \advance\tempcount1\relax
    \unless\ifnum\tempcount>#2\repeat
}
\makeatother

\newcommand*{\MyTabularEntries}{%
       Row & dataset & some numbers \\,
       \unexpanded{\cmidrule(r){1-1}\cmidrule(lr){2-2}\cmidrule(l){3-3}},
       3 & A & 10 \\,
       4 & B & 11 \\,
       5 & C & 12 \\,
       \unexpanded{\cmidrule{1-3}},
       7 & D & 48 \\,
       8 & E & 144 \\,
}%

\newcounter{RowNumber}
\NewDocumentCommand{\InsertTable}{%
    O{1-10}% #1 = range of lines to print, defaults to all lines from 1-99
    m%           #2 = table title
    m%           #3 = list of entries (terminated by comma).
}{%
    \processlist{\csdef}{#1}%
    \ResetTableTokens%
    \setcounter{RowNumber}{0}%
    \foreach \Entry in #3 {%
        \stepcounter{RowNumber}%
        \ifcsdef{Row \arabic{RowNumber}}{%
            \eAddTableTokens{\Entry}%
        }{%
            %% This row number was not requested so skip it
        }%
    }%
    \begin{tabular}{lll}
        \toprule
        \multicolumn{3}{c}{#2} \\
        \PrintTableTokens
        \bottomrule
    \end{tabular}%
    %  Clear the desired rows list
    \processlist{\csundef}{#1}%
}

\begin{document}

    \InsertTable{All Rows}{\MyTabularEntries}%

    \par\medskip
    \InsertTable[1-5]{Rows 1-5}{\MyTabularEntries}%

    \par\medskip
    \InsertTable[1,2,4,6-10]{Rows 1,2,4,6-10}{\MyTabularEntries}%
\end{document}
  • See my answer for an implementation of a handler of the list of rows and ranges. You can incorporate that into your code if you like. – Hood Chatham Aug 24 '18 at 10:31
  • @HoodChatham: Thanks. Have updated the answer to adapt your solution to the range parsing. – Peter Grill Aug 24 '18 at 22:09
3

This isn't a complete answer answer because I think Peter Grill's answer is pretty good. I am just providing here a macro to process a list of individual rows and ranges to work with Peter's code.

\newcount\tempcount
\def\processlist#1{\processlist@#1,\@nil}
\def\processlist@#1,{%
    \in@-{#1}%
    \ifin@
        \processrange#1\@nil
    \else
        \csgdef{Row #1}{}%
    \fi
    \@ifnextchar\@nil{\@gobble}{\processlist@}%
}

\def\processrange#1-#2\@nil{%
    \tempcount=#1\relax
    \loop
        \csgdef{Row \the\tempcount}{}%
        \advance\tempcount1\relax
    \unless\ifnum\tempcount>#2\repeat
}

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.