20

The goal is to create the following table without having to typeset all the rows one after another but using some kind of loops like the \foreach command provided by the pgffor package

enter image description here

MWE

\documentclass{article}
\usepackage{array,booktabs,pgffor}
\newcommand{\myhrule}{\rule{1cm}{0.5pt}}
\begin{document}
%
\begin{tabular}{p{0.5cm}*{3}{>{\centering\arraybackslash}p{2cm}}}\toprule
  \(i\) & \(m\) & \(P\)  & \(y_{m}\) \\\midrule
  1&  \myhrule   &  \myhrule& \myhrule\\
  2&  \myhrule   &  \myhrule& \myhrule\\
  3&  \myhrule   &  \myhrule&\myhrule\\
  4&  \myhrule   &  \myhrule&\myhrule\\
  5&  \myhrule   &  \myhrule&\myhrule\\
  6&  \myhrule   &  \myhrule& \myhrule\\
  7&  \myhrule   &  \myhrule& \myhrule\\
  8&  \myhrule   &  \myhrule&\myhrule\\
  9&  \myhrule   &  \myhrule&\myhrule\\\bottomrule

\end{tabular}

\noindent
\foreach \i in {1,...,9}{\i \hspace{1cm} \myhrule \hspace{1cm} \myhrule\hspace{1cm} \myhrule \\}

%or 

\noindent
\foreach \i in {1,...,9}{\i \foreach \j in {1,...,3} {\hspace{1cm} \myhrule}\\}
%
\end{document}

4 Answers4

11

Here's a LuaLaTeX-based answer. No need for the pgffor package.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{array,booktabs}
\newcolumntype{C}[1]{>{\centering\arraybackslash}p{#1}}
\newcommand{\myhrule}{\rule{1cm}{0.5pt}}

\usepackage{luacode}
\begin{luacode}
function print_line (i)
  tex.sprint(i.."&\\myhrule&\\myhrule&\\myhrule\\\\")
end
\end{luacode}

\begin{document}
\begin{tabular}{@{} p{0.5cm} *{3}{C{2cm}} @{}}
\toprule
\(i\) & \(m\) & \(P\)  & \(y_{m}\) \\
\midrule
\directlua{ for i = 1 , 10 do print_line ( i ) end }
\bottomrule
\end{tabular}
\end{document}

Addendum: Suppose you wanted to generalize the Lua code so that it prints J rather than always 3 copies of &\\myhrule before forcing a line break. Assuming that J=5, say, all you'd have to do is (a) replace

function print_line (i)
  tex.sprint(i.."&\\myhrule&\\myhrule&\\myhrule\\\\")
end

with

function print_line (i,J)
  tex.sprint(i)
  for j=1,J do tex.sprint("&\\myhrule") end
  tex.sprint("\\\\")
end

and (b) change the function call

print_line ( i )

to

print_line ( i , 5)

in the argument of the subsequent \directlua directive in the tabular environment.

Mico
  • 506,678
  • Thank you for your rely. It seems straightforward and elegant with LuaLaTeX. I use to compile with pdfLaTeX. Is there a difference in the output between the two engines? – Hafid Boukhoulda Mar 02 '19 at 12:25
  • 1
    Assuming you have a reasonably up to date TeX distribution, any differences between the outputs produced by the two engines should be very minor much of the time. LuaTeX does use a different approach to paragraph building; in principle, there could be differences in line breaks and hyphenations. In my own work, though, I have yet to come across a practical instance of different line breaks. See the posting Differences between pdfLaTeX and LuaLaTeX and the links therein for a discussion of how to go about switching from pdfLaTeX to LuaLaTeX. – Mico Mar 02 '19 at 12:43
9

First implementation:

\documentclass{article}
\usepackage{array,booktabs}
\usepackage{xparse}

\newcommand{\myhrule}{\rule{1cm}{0.4pt}}

\ExplSyntaxOn

\NewDocumentCommand{\makeruledtabular}{mm}
 {% #1 = number of rows, #2 = header
  \begin{tabular}{r w{c}{2cm} w{c}{2cm} @{}}
  \toprule
  #2 \\
  \midrule
  \int_step_function:nN {#1} \__hafid_ruledtabular_line:n
  \bottomrule
  \end{tabular}
 }

\cs_new_protected:Nn \__hafid_ruledtabular_line:n
 {
  #1 & \myhrule & \myhrule \\
 }

\ExplSyntaxOff

\begin{document}

\makeruledtabular{10}{\multicolumn{1}{c}{\(i\)} & \(P\) & \(y_{m}\) }

\end{document}

enter image description here

More general implementation: the number of columns is determined from the header.

\documentclass{article}
\usepackage{array,booktabs}
\usepackage{xparse}

\newcommand{\myhrule}{\rule{1cm}{0.4pt}}

\ExplSyntaxOn

\NewDocumentCommand{\makeruledtabular}{mm}
 {% #1 = number of rows, #2 = header
  \hafid_ruledtabular:nn { #1 } { #2 }
 }

\seq_new:N \l__hafid_ruledtabular_header_seq
\tl_new:N \l__hafid_ruledtabular_first_tl

\cs_new_protected:Nn \hafid_ruledtabular:nn
 {
  % absorb the header as a sequence
  \seq_set_split:Nnn \l__hafid_ruledtabular_header_seq { & } { #2 }
  % split off the first item, which should be centered
  \seq_pop_left:NN \l__hafid_ruledtabular_header_seq \l__hafid_ruledtabular_first_tl
  % Define the auxiliary function based on the number of items in the header
  % At the end, if the header is 'A & B & C & D`, the function will be
  % defined to do '#1 & \myhrule & \myhrule & \myhrule \\', where #1 stands
  % for the current index in the loop
  \cs_set_protected:Nx \__hafid_ruledtabular_line:n
   {
    ##1
    \prg_replicate:nn { \seq_count:N \l__hafid_ruledtabular_header_seq }
     { & \exp_not:N \myhrule }
    \exp_not:N \\
   }
  \begin{tabular}
   {
    r
    *{ \seq_count:N \l__hafid_ruledtabular_header_seq } { w{c}{2cm} }
    @{}
   }
  \toprule
  \multicolumn{1}{c}{\tl_use:N \l__hafid_ruledtabular_first_tl} &
  \seq_use:Nn \l__hafid_ruledtabular_header_seq { & } \\
  \midrule
  \int_step_function:nN {#1} \__hafid_ruledtabular_line:n
  \bottomrule
  \end{tabular}
 }

\ExplSyntaxOff


\begin{document}

\makeruledtabular{10}{\(i\) & \(P\) & \(y_{m}\) }

\bigskip

\makeruledtabular{15}{A & B & C & D}

\end{document}

enter image description here

The idea is that loop of the form ..._function:... will deliver the whole loop before anything else is processed, so in the case of a three column table with three rows we will get

\__hafid_ruledtabular_line:n { 1 }
\__hafid_ruledtabular_line:n { 2 }
\__hafid_ruledtabular_line:n { 3 }

and only after this TeX will start to process the first item, therefore getting

1 & \myhrule & \myhrule \\
2 & \myhrule & \myhrule \\
3 & \myhrule & \myhrule \\

yielding the full table body.

egreg
  • 1,121,712
9

A simple solution with pgfplotstable.

I've created a table of the desired number of rows from scratch with \pgfplotstablenew and then display it with \pgfplotstabletypeset.

The column styles set with \pgfplotstableset are fully customizable.

\documentclass{article}
\usepackage{array,booktabs,pgffor}
\newcommand{\myhrule}{\rule{1cm}{0.5pt}}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.14}
\begin{document}
%set the columns style and content
\pgfplotstableset{
    create on use/new/.style={create col/expr={\pgfplotstablerow+1}},
    columns/new/.style={column name={\(i\)},column type={p{0.5cm}}},
    create on use/emme/.style={create col/set={\myhrule}},
    columns/emme/.style={column name={\(m\)},string type, column type={>{\centering\arraybackslash}p{2cm}}},
    create on use/pi/.style={create col/copy={emme}},
    columns/pi/.style={column name={\(P\)},string type, column type={>{\centering\arraybackslash}p{2cm}}},
    create on use/yup/.style={create col/copy={emme}},
    columns/yup/.style={column name={\(y_{m}\)},string type, column type={>{\centering\arraybackslash}p{2cm}}},
    }
%create a table with the desidered number of rows
\pgfplotstablenew[
    columns={new, emme, pi, yup}
    ]{9}% <--- put here the number of rows you like
    \loadedtable
%display the table
\pgfplotstabletypeset[
    every last row/.style={after row=\bottomrule},
    every head row/.style={before row=\toprule,after row=\midrule},
    ]\loadedtable

\end{document}

enter image description here

CarLaTeX
  • 62,716
5

Perhaps something like this (updated based on @Mico's comments):

\documentclass[12pt]{article}
\usepackage{array,longtable,booktabs}
\newcount\fooo
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
%some help from here
%https://tex.stackexchange.com/questions/472554/filling-table-automatic-with-dates-and-daynames/472561#472561
\newcommand{\myhrule}{\rule{1cm}{0.5pt}}
    \newcounter{mycntr}
    \setcounter{mycntr}{1}
    \begin{document}
    \def\tabledata{} \fooo=30
    \loop
   \addto\tabledata{\themycntr\stepcounter{mycntr} &\myhrule  &\myhrule &\myhrule\\}
    \advance \fooo -1
    \ifnum \fooo>0
    \repeat 

    \begin{longtable}{cccc}
        \toprule
        $i$&$m$&$p$&$y_m$\\
        \midrule
        \tabledata
        \bottomrule
    \end{longtable}

\end{document}

you will get:

enter image description here