Median of Set of Predefined Elements

Update: l3sort was used in a previous version, its macros are contained in expl3 now.

Luckily for sorting the sequence of numbers (I assumed integer values only here) there is support in expl3.

The rest is just code to determine the middle position of the indices. As it stands, the code is not expandable, however, since \seq_sort:Nn is not expandable and the \int_set:Nn prevents expansion as well.

\documentclass{article}

\usepackage{xparse}


\ExplSyntaxOn

\cs_generate_variant:Nn \seq_item:Nn {NV}

\NewDocumentCommand{\median}{m}{%
  \seq_set_from_clist:Nn \l_tmpa_seq {#1}
  \seq_sort:Nn \l_tmpa_seq {%
    \int_compare:nNnTF { ##1 } > { ##2 }
    { \sort_reversed: }
    { \sort_ordered: }
  }
  \int_set:Nn \l_tmpa_int {\seq_count:N \l_tmpa_seq }
  \int_if_odd:nTF { \l_tmpa_int } {%
    \int_set:Nn \l_tmpb_int {\l_tmpa_int / 2}
    \int_set:Nn \l_tmpa_int {\l_tmpb_int}
  }{%
    \int_set:Nn \l_tmpb_int {\l_tmpa_int / 2 }
    \int_set:Nn \l_tmpa_int {\l_tmpb_int + 1}
  }
  \fp_eval:n {(\seq_item:NV \l_tmpa_seq \l_tmpb_int + \seq_item:NV \l_tmpa_seq \l_tmpa_int)/2}
}

\ExplSyntaxOff

\begin{document}

\def\waterAa{82}
\def\waterAb{51}
\def\waterAc{144}
\def\waterAd{84}
\def\waterAe{120}
\def\waterAf{148}
\def\waterAg{148}
\def\waterAh{108}
\def\waterAi{160}
\def\waterAj{86}


The median is \median{82,51,144,84,120,148,148,108,160,86}

The median is \median{\waterAa, \waterAb, \waterAc, \waterAd, \waterAe, \waterAf, \waterAg, \waterAh, \waterAi, \waterAj}

\end{document}

enter image description here


You can use floating point numbers; the trick is to expand the values when absorbing them.

\documentclass{article}

\usepackage{xparse}
\usepackage{expl3}

\ExplSyntaxOn

\NewDocumentCommand{\median}{m}
 {
  \svend_median:x { #1 }
 }

\clist_new:N \l__svend_median_clist
\int_new:N \l__svend_median_int

\cs_new_protected:Nn \svend_median:n
 {
  % set a comma separated list
  \clist_set:Nn \l__svend_median_clist { #1 }
  % sort it numerically
  \clist_sort:Nn \l__svend_median_clist
   {
    \fp_compare:nTF { ##1 > ##2 }
     { \sort_return_swapped: }
     { \sort_return_same: }
   }
  % compute the number of items
  \int_set:Nn \l__svend_median_int { \clist_count:N \l__svend_median_clist }
  \int_if_odd:nTF {\l__svend_median_int }
   {% if the number is odd, return the middle item
    \clist_item:Nn \l__svend_median_clist { (\l__svend_median_int + 1)/2 }
   }
   {% otherwise the average of the middle two elements
    \fp_eval:n
     {
      ( 
       \clist_item:Nn \l__svend_median_clist { \l__svend_median_int/2 }
       +
       \clist_item:Nn \l__svend_median_clist { \l__svend_median_int/2 + 1 }
      )/2
     }
   }
 }
\cs_generate_variant:Nn \svend_median:n { x }
\ExplSyntaxOff

\begin{document}

\def\waterAa{82}
\def\waterAb{51}
\def\waterAc{144}
\def\waterAd{84}
\def\waterAe{120}
\def\waterAf{148}
\def\waterAg{148}
\def\waterAh{108}
\def\waterAi{160}
\def\waterAj{86}


The median is \median{82,51,144,84,120,148,148,108,160,86}

The median is \median{
  \waterAa, \waterAb, \waterAc, \waterAd, \waterAe, 
  \waterAf, \waterAg, \waterAh, \waterAi, \waterAj
}

The median is \median{
  \waterAa, \waterAb, \waterAc, \waterAd, \waterAe, 
  \waterAf, \waterAg, \waterAh, \waterAi, %\waterAj
}

The median is \median{1,2,3,4}

The median is \median{1,2,3}

The median is \median{3.3,4.4,5.503,6.01}

The median is \median{3.3,4.4,5.503}

\end{document}

enter image description here

Tags:

Latex3

Expl3