19

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

4 Answers 4

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

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.

2
  • 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? Mar 2, 2019 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 2, 2019 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.

4
  • Thank you very much for your reply. I have some troubles with the LaTeX3 syntax I am still with LaTeX2e. I should make the jump but it is not easy for me. Mar 2, 2019 at 12:13
  • 1
    @HafidBoukhoulda I added some comments to the second implementation.
    – egreg
    Mar 2, 2019 at 13:26
  • @egreg How can I make a long table contains 200 rows? Mar 4, 2019 at 7:43
  • @minhthien_2016 You have to use longtable instead of tabular.
    – egreg
    Mar 4, 2019 at 8:10
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

9
  • 2
    The OP seems commendably averse to using vertical rules in the tabular environment.
    – Mico
    Mar 2, 2019 at 11:27
  • @Mico thanks for the remark. I adapted this from my past answer. I will incorporate your comments once I'm back home ;-) Mar 2, 2019 at 11:32
  • Thank you very much for your reply. I wonder if there is a way the replace the \loop block in your code with a \foreach block? Mar 2, 2019 at 12:02
  • @HafidBoukhoulda then, afaik, you must use pgf package. I'm not sure we can use that here. But I will note it as well atop Mico's comments. Mar 2, 2019 at 12:06
  • 1
    @Mico Updated my answer with the myhrule triplets. Mar 4, 2019 at 7:10

You must log in to answer this question.

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