3

Now I want to put the data organized in two array in a table. The procedure works, but I have to write and call it once for the x values and once for the y values. Is it possible to have a single NewDocumentCommand which can be used for both? Thank you very much for any advice.

Here the code:

\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx,booktabs} 
%
%
\ExplSyntaxOn
%
\fparray_new:Nn \g_x {6}
\fparray_gset:Nnn \g_x {1}{0.907}
\fparray_gset:Nnn \g_x {2}{0.875}
\fparray_gset:Nnn \g_x {3}{0.845}
\fparray_gset:Nnn \g_x {4}{0.817}
\fparray_gset:Nnn \g_x {5}{0.701}
\fparray_gset:Nnn \g_x {6}{0.613}
%
\fparray_new:Nn \g_y {6}
\fparray_gset:Nnn \g_y {1}{27}
\fparray_gset:Nnn \g_y {2}{28}
\fparray_gset:Nnn \g_y {3}{29}
\fparray_gset:Nnn \g_y {4}{30}
\fparray_gset:Nnn \g_y {5}{35}
\fparray_gset:Nnn \g_y {6}{40}
%
\NewDocumentCommand{\calcnumd}{o m}
  {\IfValueTF{#1}
     {\num[round-mode = figures, round-precision = #1, round-integer-to-decimal]{\fp_to_decimal:n{#2}}}
     {\num{\fp_to_decimal:n{#2}}}
  }
%
\NewDocumentCommand{\calcx}{o m}
  {
     \fp_set:Nn \indice {\fparray_item:Nn \g_x {#2}}     
     \calcnumd[#1]{\indice}
  }
%
\NewDocumentCommand{\calcy}{o m}
  {
     \fp_set:Nn \indice {\fparray_item:Nn \g_y {#2}}     
     \calcnumd[#1]{\indice}
  }
%
\ExplSyntaxOff
%
%
\begin{document}

The experimental data are:

\begin{tabular}{l|llllll}
\toprule
$P/\si{\bar}$ & \calcx[4]{1} & \calcx[4]{2} & \calcx[4]{3} & \calcx[4]{4} & \calcx[4]{5} & \calcx[4]{6} \\
$V/\si{\liter}$ & \calcy{1} & \calcy{2} & \calcy{3} & \calcy{4} & \calcy{5} & \calcy{6} \\
\bottomrule
\end{tabular}

\end{document}
1
  • Please, don't use names such as \g_x that don't conform to the naming scheme of expl3. Also \indice is wrong.
    – egreg
    Aug 6 '20 at 7:55
2

You can combine the \calcx and \calcy functions into a single function simply by replacing \fparray_item:Nn with \fparray_item:cn and having x or y as a parameter to the new function:

\NewDocumentCommand{\calc}{omm}
{
    \fp_set:Nn \g_indice_fp {\fparray_item:cn {g_#2} {#3}}
    \calcnumd[#1]{\g_indice_fp}
}

Notice that I have also replaced the \indice in the OP with an expl3 fp variable \g_indice_fp. This is called as \calc[4]{x}{4} or \calc{y}{5}.

Having done this it is natural to go a step further and replace the multiple calls \calcy{1}, ..., \calcy{6} with a single function \Calc{y}{1}{6}. To do this we just need to add \int_step_inline:nnn and an ampersand to the previous definition:

\NewDocumentCommand{\Calc}{ommm}
{
   \int_step_inline:nnn {#3} {#4}
   {
     \fp_gset:Nn \g_indice_fp {\fparray_item:cn {g_#2} {##1}}
     & \calcnumd[#1]{\g_indice_fp}
   }
}

Here is the output where the first table uses \calc and the second uses \Calc:

enter image description here

Here is the full code:

\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx,booktabs}
%
%
\ExplSyntaxOn
%
\fparray_new:Nn \g_x {6}
\fparray_gset:Nnn \g_x {1}{0.907}
\fparray_gset:Nnn \g_x {2}{0.875}
\fparray_gset:Nnn \g_x {3}{0.845}
\fparray_gset:Nnn \g_x {4}{0.817}
\fparray_gset:Nnn \g_x {5}{0.701}
\fparray_gset:Nnn \g_x {6}{0.613}
%
\fparray_new:Nn \g_y {6}
\fparray_gset:Nnn \g_y {1}{27}
\fparray_gset:Nnn \g_y {2}{28}
\fparray_gset:Nnn \g_y {3}{29}
\fparray_gset:Nnn \g_y {4}{30}
\fparray_gset:Nnn \g_y {5}{35}
\fparray_gset:Nnn \g_y {6}{40}
%
\NewDocumentCommand{\calcnumd}{o m}
  {\IfValueTF{#1}
     {\num[round-mode = figures, round-precision = #1, round-integer-to-decimal]{\fp_to_decimal:n{#2}}}
     {\num{\fp_to_decimal:n{#2}}}
  }
%
\fp_new:N \g_indice_fp
\NewDocumentCommand{\calc}{omm}
{
    \fp_set:Nn \g_indice_fp {\fparray_item:cn {g_#2} {#3}}
    \calcnumd[#1]{\g_indice_fp}
}
\cs_generate_variant:Nn \fparray_item:Nn {cn}
% \Calc[offset]{x/y}{start}{finish}
\NewDocumentCommand{\Calc}{ommm}
{
   \int_step_inline:nnn {#3} {#4}
   {
     \fp_gset:Nn \g_indice_fp {\fparray_item:cn {g_#2} {##1}}
     & \calcnumd[#1]{\g_indice_fp}
   }
}
\cs_generate_variant:Nn \fp_set:Nn {Nx}
\cs_generate_variant:Nn \fparray_item:Nn {cn}

\ExplSyntaxOff
%
%
\begin{document}

The experimental data are:

\begin{tabular}{l|llllll}
\toprule
$P/\si{\bar}$ & \calc[4]{x}{1} & \calc[4]{x}{2} & \calc[4]{x}{3} & \calc[4]{x}{4} & \calc[4]{x}{5} & \calc[4]{x}{6} \\
$V/\si{\liter}$ & \calc{y}{1} & \calc{y}{2} & \calc{y}{3} & \calc{y}{4} & \calc{y}{5} & \calc{y}{6} \\
\bottomrule
\end{tabular}

\bigskip

\begin{tabular}{l|llllll}
\toprule
$P/\si{\bar}$   \Calc[4]{x}{1}{6}\\
$V/\si{\liter}$ \Calc{y}{1}{6} \\
\bottomrule
\end{tabular}

\end{document}

Finally, here is a third version where I have replaced the array names \g_x and \g_y with names that follow the standard conventions and defined a new command \ArraySet to set these arrays:

\ArraySet{x}{0.907, 0.875, 0.845, 0.817, 0.701, 0.613}
\ArraySet{y}{27, 28, 29, 30, 35, 40}

The output is the same as before. Here is the updated code:

\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx,booktabs}
%
%
\ExplSyntaxOn
%
\fparray_new:Nn \g_stalks_x_fparray {6}
\fparray_new:Nn \g_stalks_y_fparray {6}

\int_new:N \l_array_index_int
\NewDocumentCommand\ArraySet{mm}
{
   \clist_set:Nn \l_tmpa_clist {#2}
   \int_zero:N \l_array_index_int
   \clist_map_inline:Nn \l_tmpa_clist
   {
        \int_incr:N \l_array_index_int
        \fparray_gset:cVo {g_stalks_#1_fparray} \l_array_index_int {##1}
   }
}
%
\NewDocumentCommand{\calcnumd}{o m}
  {\IfValueTF{#1}
     {\num[round-mode = figures, round-precision = #1, round-integer-to-decimal]{\fp_to_decimal:n{#2}}}
     {\num{\fp_to_decimal:n{#2}}}
  }
%
\fp_new:N \g_indice_fp
\NewDocumentCommand{\calc}{omm}
{
    \fp_set:Nn \g_indice_fp {\fparray_item:cn {g_stalks_#2_fparray} {#3}}
    \calcnumd[#1]{\g_indice_fp}
}
\cs_generate_variant:Nn \fparray_item:Nn {cn}
% \Calc[offset]{x/y}{start}{finish}
\NewDocumentCommand{\Calc}{ommm}
{
   \int_step_inline:nnn {#3} {#4}
   {
     \fp_gset:Nn \g_indice_fp {\fparray_item:cn {g_stalks_#2_fparray} {##1}}
     & \calcnumd[#1]{\g_indice_fp}
   }
}
\cs_generate_variant:Nn \fp_set:Nn {Nx}
\cs_generate_variant:Nn \fparray_item:Nn {cn}
\cs_generate_variant:Nn \fparray_gset:Nnn {cVo}

\ExplSyntaxOff
%
\ArraySet{x}{0.907, 0.875, 0.845, 0.817, 0.701, 0.613}
\ArraySet{y}{27, 28, 29, 30, 35, 40}

\begin{document}

The experimental data are:

\begin{tabular}{l|llllll}
\toprule
$P/\si{\bar}$ & \calc[4]{x}{1} & \calc[4]{x}{2} & \calc[4]{x}{3} & \calc[4]{x}{4} & \calc[4]{x}{5} & \calc[4]{x}{6} \\
$V/\si{\liter}$ & \calc{y}{1} & \calc{y}{2} & \calc{y}{3} & \calc{y}{4} & \calc{y}{5} & \calc{y}{6} \\
\bottomrule
\end{tabular}

\bigskip

\begin{tabular}{l|llllll}
\toprule
$P/\si{\bar}$   \Calc[4]{x}{1}{6}\\
$V/\si{\liter}$ \Calc{y}{1}{6} \\
\bottomrule
\end{tabular}

\end{document}
3
  • The "further" solution with Calc also solves many other problems related to the handling of these arrays. Aug 5 '20 at 15:18
  • @AlbyStalks Glad it's helpful. I have just added an \ArraySet command as I setting the arrays manually looks painful to me. Rather than hard coding the length of the array as 6 you could also use the \ArraySet command to construct the array, using \clist_count:N to get the required length.
    – user30471
    Aug 5 '20 at 22:36
  • There's a lot of useless material, I'm afraid.
    – egreg
    Aug 6 '20 at 8:22
2

Please, do avoid such things as \g_x. The name should be something like

\g_albystalks_x_fparray

One of the problems in the current state of LaTeX is that packages use conflicting names for their internal macros. A uniform naming method can avoid such issues.

Now, let's tackle your problem.

There is no need to use \indice (another bad name): \fp_to_decimal:n will take care of expanding its argument.

A different approach with symbolic names can avoid the issue of \g_x and keep input simple.

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

\ExplSyntaxOn

%%% user level commands
\NewDocumentCommand{\calcnumd}{o m}
 {
  \IfValueTF{#1}
   {
    \num
     [
      round-mode = figures,
      round-precision = #1,
      round-integer-to-decimal
     ]
     { \fp_to_decimal:n {#2} }
   }
   { \num{ \fp_to_decimal:n {#2} } }
  }

\NewDocumentCommand{\definearray}{mm}
 {
  \albystalks_array_define:nn { #1 } { #2 }
 }

\NewDocumentCommand{\usearray}{mmm}
 {% #1 = array symbolic name
  % #2 = template
  % #3 = separator
  \albystalks_array_use:nnn { #1 } { #2 } { #3 }
 }

\NewExpandableDocumentCommand{\arraycount}{m}
 {
  \albystalks_array_count:n { #1 }
 }

\NewExpandableDocumentCommand{\arrayitem}{mm}
 {
  \albystalks_array_item:nn { #1 } { #2 }
 }

%%% variables and scratch functions
\seq_new:N \l__albystalks_array_seq
\cs_new:Nn \__albystalks_array:n {}

%%% internal functions
\cs_new_protected:Nn \albystalks_array_define:nn
 {
  \fparray_new:cn { g_albystalks_#1_fparray } { \clist_count:n { #2 } }
  \int_step_inline:nn { \clist_count:n { #2 } }
   {
    \fparray_gset:cnn { g_albystalks_#1_fparray } { ##1 } { \clist_item:nn { #2 } { ##1 } }
   }
 }

\cs_new_protected:Nn\albystalks_array_use:nnn
 {
  \seq_clear:N \l__albystalks_array_seq
  \cs_gset_protected:Nn \__albystalks_array:n { #2 }
  \int_step_inline:nn { \fparray_count:c { g_albystalks_#1_fparray } }
   {
    \seq_put_right:Nx \l__albystalks_array_seq
     {
      \__albystalks_array:n
       {
        \fparray_item:cn { g_albystalks_#1_fparray } { ##1 }
       }
     }
   }
  \seq_use:Nn \l__albystalks_array_seq { #3 }
 }

\cs_new:Nn \albystalks_array_item:nn
 {
  \fparray_item:cn { g_albystalks_#1_fparray } { #2 }
 }

\cs_new:Nn \albystalks_array_count:n
 {
  \fparray_count:c { g_albystalks_#1_fparray }
 }

\ExplSyntaxOff

\definearray{x}{0.907,0.875,0.845,0.817,0.701,0.613}
\definearray{y}{27,28,29,30,35,40}

\begin{document}

The experimental data are:

\begin{tabular}{
  l % header
  *{\arraycount{x}}{l} % as many cols as the x array
}
\toprule
$P$ (\si{\bar})   & \usearray{x}{\calcnumd[4]{#1}}{&} \\
$V$ (\si{\liter}) & \usearray{y}{\calcnumd{#1}}{&} \\
\bottomrule
\end{tabular}

\end{document}

With the c argument specifier, TeX is instructed to form a control sequence from the (variable) data in the argument.

Simpler strategies are included for populating an array and extracting items or the number thereof from a defined array.

The seemingly complicated \usearray macro has as first argument the symbolic name of a defined array; the second argument is a template where #1 stands for the current item, because the items will be stored one by one and then delivered; the third argument is the separator between items.

enter image description here

Another example of usage:

The third item in the ``x'' array is
\begin{enumerate}
\item \arrayitem{x}{3} (raw)
\item \num{\arrayitem{x}{3}} (with \texttt{\string\num})
\item \calcnumd{\arrayitem{x}{3}}
\item \calcnumd[2]{\arrayitem{x}{3}}
\end{enumerate}

enter image description here

1
  • The names to avoid were used only here for the examples. However I will follow your suggestion for a more uniform naming method. The hints I received will be very useful to prepare a problem where for a series of experimental data (x_i,y_i), the regression line is searched with the method of least squares. Calculations and typesetting using LaTeX/LaTeX3. Aug 6 '20 at 12:42

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.