4

The code would like this, but how to finish the rest ?

\documentclass{article}

\begin{document}

\ExplSyntaxOn

\NewDocumentCommand{\average}{m}{%
}

\ExplSyntaxOff

\average{1,3.7,5} % would return 3.233

\average{1,3.7,5,3.2*2,7.9} % would return 4.8.  the argument number is arbitrary but limited

\end{document}
0

4 Answers 4

11

The following defines a fully expandable variant of your \average macro. I also added an optional argument to provide the rounding precision.

You don't need anything else to also access variables, be they defined as macros or fp variables.

\documentclass{article}

\ExplSyntaxOn
\cs_new:Npn \xcn_mean:n #1
  { \fp_eval:n { ( \clist_use:nn {#1} { + } ) / \clist_count:n {#1} } }
\NewExpandableDocumentCommand \average { o m }
  {
    \IfNoValueTF {#1}
      { \xcn_mean:n {#2} }
      { \fp_eval:n { round ( \xcn_mean:n {#2}, #1 ) } }
  }
\fp_new_variable:n { aaa }
\fp_set_variable:nn { aaa } { 3.7 }
\ExplSyntaxOff

\begin{document}
\average[3]{1,aaa,5} % would return 3.233

\average{1,3.7,5,3.2*2,7.9} % would return 4.8.  the argument number is arbitrary but limited
\end{document}

An extended variant that also allows to calculate the mean of the return values of a function. I use expkv-cs to split the optional argument as a key=value argument with the two keys round and f. The notation V:~ in the key definition list is the same as \exp_args:NV for keys in expkv and the other related packages (note that the ~ is only to be used in \ExplSyntaxOn, outside of that scope it should be V: ).

\documentclass{article}

\usepackage{expkv-cs}

\ExplSyntaxOn
\cs_new:Npn \xcn_mean:n #1
  { \fp_eval:n { ( \clist_use:nn {#1} { + } ) / \clist_count:n {#1} } }
\cs_new:Npn \xcn_mean_function:nn #1#2
  {
    \fp_eval:n
      {
        ( \clist_map_tokens:nn {#2} { \__xcn_mean_function_aux:nn {#1} } )
        / \clist_count:n {#2}
      }
  }
\cs_new:Npn \__xcn_mean_function_aux:nn #1#2 { +(#1(#2)) }

\NewExpandableDocumentCommand \average { O{} m }
  { \__xcn_average:nn {#1} {#2} }
\ekvcSplitAndForward \__xcn_average:nn \__xcn_average_aux:nnn
  {
     V:~ round = \c_novalue_tl
    ,V:~ f = \c_novalue_tl
  }
\cs_new:Npn \__xcn_average_aux:nnn #1#2#3
  {
    % #1: round
    % #2: f
    % #3: clist
    \tl_if_novalue:nTF {#1}
      { \__xcn_average_aux:nn {#2} {#3} }
      { \fp_eval:n { round ( \__xcn_average_aux:nn {#2} {#3}, #1 ) } }
  }
\cs_new:Npn \__xcn_average_aux:nn #1#2
  {
    \tl_if_novalue:nTF {#1}
      { \xcn_mean:n {#2} }
      { \xcn_mean_function:nn {#1} {#2} }
  }

\fp_new_variable:n { aaa }
\fp_set_variable:nn { aaa } { 3.7 }
\fp_new_function:n { sq }
\fp_set_function:nnn { sq } { x } { x**2 }
\ExplSyntaxOff

\begin{document}
\average[round=3]{1,aaa,5} % would return 3.233

\average{1,3.7,5,3.2*2,7.9} % would return 4.8.  the argument number is arbitrary but limited

\average[f=sq]{1, 2, 3, 4} % 30/4 = 7.5
\end{document}
4
  • Is it possible to visit each item in \average and make a progamm that add item one by one with a loop ? Commented Oct 29, 2024 at 6:49
  • @XCN why do you want that? I don't see the advantage, \clist_use:nn {#1} { + } is very simple and concise code. Of course it's possible to loop manually, as I said, I just don't see the reason to. Commented Oct 29, 2024 at 7:05
  • If I need a function and the known variables are stored in a list , then it need to visit the item. Commented Oct 29, 2024 at 7:23
  • @XCN just for variables you don't need that, but if you want to get the mean of a function applied to each item in turn then you're right. See my latest edit, which adds that possibility. Commented Oct 29, 2024 at 8:30
5

The expandable \average macro can be created in OpTeX using \expr and \foreach:

\optdef\average[3]#1{\immediateassignment\tmpnum=0
   \expr[\the\opt]{(0\foreach#1,\do##1,{+(##1)\incrtmpnum})/\the\tmpnum}}
\def\incrtmpnum{\immediateassignment\advance\tmpnum by1 }

\average{1,3.7,5} % would return 3.233

\average[1]{1,3.7,5,3.2*2,7.9} % would return 4.8.  the argument number is arbitrary but li

\message{\average[5]{2,3}}

\bye
5

If the main point is learn expl3, this is the wrong answer. But if the goal is make easy descriptives statistics as the mean or median, or some more complex, consider include the R language in the LateX document:

mwe

File name: mwe.Rnw (locally, use mwe.Rtex in Overleaf)

\documentclass{article}
\parskip1em\parindent0pt
\begin{document}
<<echo=F>>=
require(knitr)
@
Mean of \Sexpr{combine_words(c(1,3.7,5))} would return roughly
\Sexpr{round(mean(c(1,3.7,5)),2)} (more precisely,
\Sexpr{mean(c(1,3.7,5))})  
<<data,echo=F>>=
# complex data better in a object x
x <- c(1,3.7,5,3.2*2,7.9)
@
Mean of x  values (\Sexpr{x}) is \Sexpr{mean(x)} with a SD of
\Sexpr{sd(x)} (rounded \Sexpr{round(sd(x),1)}) but the median is
\Sexpr{median(x)}. 
<<echo=F,fig.cap="Average of x in a box and wisker plot",fig.pos="h!">>=
boxplot(x,xlab="My x values")
@
\end{document}
0
4

It's very hard to follow your journey along fp variables…

However, it's possible to define an expandable \average command that copes with each of your various methods.

\documentclass{article}

\ExplSyntaxOn

\NewExpandableDocumentCommand{\average}{O{20}m}
 {% #1 = accuracy, #2 = list of fp expressions
  \xcn_average:nn {#1} {#2}
 }

\cs_new:Nn \xcn_average:nn
 {
  \fp_eval:n { round ( 0 \clist_map_function:nN {#2} \__xcn_average_item:n , #1 ) }
 }
\cs_new:Nn \__xcn_average_item:n
 {
  + \fp_eval:n {#1}
 }

%% method with fp variables
\fp_new_variable:n { aaa }
\fp_set_variable:nn { aaa } { 3.5 }

% method with commands
\newcommand{\bbb}{4.5}

\ExplSyntaxOff

\begin{document}

\average{2,4,aaa,\bbb,pi}

\average[3]{2,4,aaa,\bbb,pi}

\edef\test{\average[4]{2,4,aaa,\bbb,pi}}
\texttt{\meaning\test}

\end{document}

output

7
  • It seems that I did't express myself clearly. My purpose is that , if I calulate z=2*x+3*y , and let x=5,y=6 . then define a function that can calculate z , and treat {5,6} as a list to be used by expl3 and the result is 2*5+3*6=28. Commented Oct 29, 2024 at 9:04
  • 4
    This doesn’t qualify as an average, does it? Commented Oct 29, 2024 at 9:13
  • Yes, it goes beyond the scope of the topic. Commented Oct 29, 2024 at 9:17
  • What O{20} do ? keep 20 decimal places? Why there is a 0 in round(0 \clist_… ? Commented Oct 29, 2024 at 14:19
  • 1
    @egreg 21 decimal digits are possible in l3fp's output, for instance \fpeval{1e-21}. Better check for an optional argument :) Commented Oct 30, 2024 at 12:33

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.