Position of largest element in a list

Here is an etoolbox:

enter image description here

\documentclass{article}

\usepackage{expl3,etoolbox}

\ExplSyntaxOn
  \cs_new_eq:NN \calc \fp_eval:n
\ExplSyntaxOff

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\makeatletter
\newcounter{maxindex}
\newcommand{\findmaxindex}[1]{%
  \@tempcnta=0% Counter for stepping through elements
  \setlength{\@tempdima}{-\maxdimen}% "Smallest" number as a length/dimension
  \renewcommand*{\do}[1]{%
    \advance\@tempcnta by 1% Step to next element
    \ifdimgreater{##1pt}{\@tempdima}{\setlength{\@tempdima}{##1pt}\setcounter{maxindex}{\@tempcnta}}{}}% Found larger element
  \docsvlist{#1}% process list to find maximum number and index
}
\makeatother

\setlength{\parindent}{0pt}% Just for this example
\begin{document}

I have the list
\[
  7, 19, 41, 31, 25, 17, 7, 3
\]
in which the largest element is $\calc{max(7, 19, 41, 31, 25, 17, 7, 3)}$.

\findmaxindex{7, 19, 41, 31, 25, 17, 7, 3}% Find maximum number index
The position number of the largest element in this \themaxindex.

\bigskip

I have the list
\[
  \valueH,\valueG,\valueF,\valueE,\valueD,\valueC,\valueB,\valueA
\]
in which the largest element is $\calc{max(\valueH,\valueG,\valueF,\valueE,\valueD,\valueC,\valueB,\valueA)}$.

\findmaxindex{\valueH,\valueG,\valueF,\valueE,\valueD,\valueC,\valueB,\valueA}% Find maximum number index
The position number of the largest element in this \themaxindex.

\end{document}

Note that it will choose as index of the first elements that is largest. The index of the maximum number is stored in the counter maxindex, available for print via \themaxindent.

The idea is to step through the list and mark each element that is found to be greater than the previous greatest element found. Using dimensions allows for working with decimal numbers.


Just using expl3 we can do this using one loop or two. A one loop version needs to work out the maximum value and track the position at the same time:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand \maxposition { m }
  {
    \svend_clist_pos_max:n {#1}
  }
\cs_new:Npn \svend_clist_pos_max:n #1
  {
    \__svend_clist_pos_max:nnnw \c_zero \c_zero { -\c_max_int }
      #1 , \q_recursion_tail , \q_recursion_stop
  }
 \cs_new:Npn \__svend_clist_pos_max:nnnw #1#2#3#4 ,
   {
     \quark_if_recursion_tail_stop_do:nn {#4} {#1}
     \fp_compare:nNnTF {#4} > {#3}
       {
         \__svend_clist_pos_max:fnnw 
           { \int_eval:n { #1 + #2 + \c_one } } \c_zero {#4}
       }
       {
         \__svend_clist_pos_max:nfnw 
           {#1} { \int_eval:n { #2 + \c_one } } {#3}
       }
  }
\cs_generate_variant:Nn \__svend_clist_pos_max:nnnw { f , nf }
\ExplSyntaxOff

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\begin{document}

\maxposition{\valueA,\valueB,\valueC,\valueD,\valueE,\valueF,\valueG,\valueH}

\end{document}

whereas a two loop version first finds the maximum then the position so there are fewer things to track in one go

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand \maxposition { m }
  {
    \svend_clist_pos_max:n {#1}
  }
\cs_new:Npn \svend_clist_pos_max:n #1
  {
    \__svend_clist_pos_max:fn
      {
        \__svend_clist_pos_max:nw { -\c_max_int }
          #1 , \q_recursion_tail , \q_recursion_stop
      } {#1}
  }
\cs_new:Npn \__svend_clist_pos_max:nw #1#2 ,
  {
    \quark_if_recursion_tail_stop_do:nn {#2} {#1}
    \fp_compare:nNnTF {#2} > {#1}
      { \__svend_clist_pos_max:nw {#2} }
      { \__svend_clist_pos_max:nw {#1} }
  }
\cs_new:Npn \__svend_clist_pos_max:nn #1#2
  {
    \__svend_clist_pos_max:nnw { 1 } {#1}
      #2 , \q_recursion_tail , \q_recursion_stop
  }
\cs_generate_variant:Nn \__svend_clist_pos_max:nn { f }
\cs_new:Npn \__svend_clist_pos_max:nnw #1#2#3 ,
  {
    \quark_if_recursion_tail_stop_do:nn {#3} {#1}
    \int_compare:nNnT {#2} = {#3}
      { \use_i_delimit_by_q_recursion_stop:nw {#1} }
    \__svend_clist_pos_max:fnw { \int_eval:n { #1 + \c_one } } {#2}
  }
\cs_generate_variant:Nn \__svend_clist_pos_max:nnw { f }


\cs_new:Npn \__svend_list_max:nw #1#2 ,
  {
    \quark_if_recursion_tail_stop_do:nn {#2} {#1}
    \int_compare:nNnTF {#2} > {#1}
      { \__svend_list_max:nw {#2} }
      { \__svend_list_max:nw {#1} }
  }
\ExplSyntaxOff

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\begin{document}

\maxposition{\valueA,\valueB,\valueC,\valueD,\valueE,\valueF,\valueG,\valueH}

\end{document}

The idea is first to find the largest entry using one mapping, then to find the position of this entry using a second mapping. Everything is expandable at the code level, so you could use \DeclareExpandableDocumentCommand here if you wanted.


Another expandable solution. No package used. (for this situation dealing only with integers, for decimals one can replace \ifnum with \ifdim up to some extent; for even more complicated situations there is, among others, xint).

\documentclass{article}

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\def\mylist{\valueA,\valueB,\valueC,\valueD,\valueE,\valueF,\valueG,\valueH}

\makeatletter
% the two routines \maxoflist and \maxposition are not optimal if the
% list elements require some costly expansion to compute their values
% this could be improved, if needed, to do this expansion only once
% I here design the thing for either litteral digit tokens or 
% \count registers or the like

% naturally one could also do a single routine with a two element
% output: (earliest) position and value of the maximum

% maximum
\def\maxoflist #1{\romannumeral0\expandafter
                    \maxoflist@a\romannumeral-`0#1,,}
\def\maxoflist@a #1,{\maxoflist@c {\numexpr#1\relax}}
\def\maxoflist@c #1#2,{%
    \ifx\relax #2\relax\expandafter\maxoflist@end
    \else\ifnum#2>#1\expandafter\expandafter\expandafter\maxoflist@update
               \else\expandafter\expandafter\expandafter\maxoflist@next
    \fi\fi {#1}{#2}}
\def\maxoflist@end    #1#2{\expandafter\space\the#1}
\def\maxoflist@update #1#2{\maxoflist@c {\numexpr#2\relax}}
\def\maxoflist@next   #1#2{\maxoflist@c {#1}}

% max position
\def\maxposition #1{\romannumeral0\expandafter
                    \maxposition@a\romannumeral-`0#1,,}
\def\maxposition@a #1,{\maxposition@c 21{\numexpr#1\relax}}
\def\maxposition@b #1%
   {\expandafter\maxposition@c\expandafter {\the\numexpr #1+\@ne}}%
\def\maxposition@c #1#2#3#4,{%
    \ifx\relax #4\relax\expandafter\maxposition@end
    \else\ifnum#4>#3\expandafter\expandafter\expandafter\maxposition@update
               \else\expandafter\expandafter\expandafter\maxposition@next
    \fi\fi {#1}{#2}{#3}{#4}}
\def\maxposition@end #1#2#3#4{ #2}
\def\maxposition@update #1#2#3#4{\maxposition@b {#1}{#1}{\numexpr#4\relax}}
\def\maxposition@next   #1#2#3#4{\maxposition@b {#1}{#2}{#3}}
\makeatother


\begin{document}

\noindent I have the list
\[
\mylist
\]
in which the largest element is $\maxoflist\mylist$ (but that is 
of no importance to me).\\[\baselineskip]
How can I get \LaTeX{} to extracting the position number 
of the largest element in a list? (In the example above, 
the answer is of course `$\maxposition\mylist$'.)

\end{document}

maxposition